el-cascader元件根據最後一級向上找到父級並設定預設值

2022-10-24 18:01:27

vue + elementUI專案中,el-cascader級聯選擇器使用頻率非常高,一些基本使用方法可以參考elementUI官方檔案,本文主要研究當介面只返回最後一級id時,如何向上找出所有父級資料,並設定元件el-cascader的預設值!

準備測試資料:方位、省、市區級聯選擇。

var list = [
  {
    parent: 0,
    value: 1,
    label: '東南',
    children: [
      {
        parent: 1,
        value: 2,
        label: '上海',
        children: [
          {parent: 2, value: 3, label: '普陀'},
          {parent: 2, value: 4, label: '黃埔'},
          {parent: 2, value: 5, label: '徐匯'}
        ]
      },
      {
        parent: 1,
        value: 7,
        label: '江蘇',
        children: [
          {parent: 7, value: 8, label: '南京'},
          {parent: 7, value: 9, label: '蘇州'},
          {parent: 7, value: 10, label: '無錫'}
        ]
      },
      {
        parent: 1,
        value: 12,
        label: '浙江',
        children: [
          {parent: 12, value: 13, label: '杭州'},
          {parent: 12, value: 14, label: '寧波'},
          {parent: 12, value: 15, label: '嘉興'}
        ]
      }
    ]
  },
  {
    parent: 0,
    value: 17,
    label: '西北',
    children: [
      {
        parent: 17,
        value: 18,
        label: '陝西',
        children: [
          {parent: 18, value: 19, label: '西安'},
          {parent: 18, value: 20, label: '延安'}
        ]
      },
      {
        parent: 17,
        value: 21,
        label: '新疆維吾爾自治區',
        children: [
          {parent: 21, value: 22, label: '烏魯木齊'},
          {parent: 21, value: 23, label: '克拉瑪依'}
        ]
      }
    ]
  }]

假設現在介面返回最後一級id陣列是[13],表示選中杭州,需要根據id:13,找到所有父級id並組成陣列 -> [1,12,13],(上面測試資料的value即id),具體方法如下:

/**
 * 針對樹形資料結構的級聯選擇器元件,後臺資料返回最後一級資料id
 * 封裝處理方法,返回樹形結構(注意此方法根據id返回對應結構的原始資料,根據不同場景,需再二次處理獲得所需資料)
 *
 * @param list 級聯選擇器全部資料
 * @param flagAttr 欄位標識(id)
 * @param values 介面最後一級id陣列
 * @param parentKey 樹形資料中的父級id欄位
 * @param childrenKey 父級的子資料陣列
 *
 * @return [treeData, ...]
 * */
export function findParentLevel(list, flagAttr, values, parentKey = 'parent', childrenKey = 'children') {
  if (!list || !list.length || !flagAttr || !Array.isArray(values)) return []
  const longList = extractTree(list, childrenKey) // 展開樹形資料
  values = values.map(value => longList.find(item => item[flagAttr] === value)).filter(Boolean)
  return makeTree(longList, parentKey, childrenKey, flagAttr, values) // 返回樹形結構資料
}

extractTree:

/**
 *
 * @param {Array} arrs 樹形資料
 * @param {string} childs 樹形資料子資料的屬性名,常用'children'
 * @param {Array} attrArr 需要提取的公共屬性陣列(預設是除了childs的全部屬性)
 * @returns
 */
export function extractTree(arrs, childs, attrArr) {
  let attrList = []
  if (!Array.isArray(arrs) && !arrs.length) return []
  if (typeof childs !== 'string') return []
  if (!Array.isArray(attrArr) || Array.isArray(attrArr) && !attrArr.length) {
    attrList = Object.keys(arrs[0])
    attrList.splice(attrList.indexOf(childs), 1)
  } else {
    attrList = attrArr
  }
  const list = []
  const getObj = (arr) => {
    arr.forEach(function(row) {
      const obj = {}
      attrList.forEach(item => {
        obj[item] = row[item]
      })
      list.push(obj)
      if (row[childs]) {
        getObj(row[childs]) // 遞迴
      }
    })
    return list
  }
  return getObj(arrs)
}

makeTree:

/**
 * 組合樹形資料結構
 * @param data 平鋪後的所有樹形資料
 * @param pid 父級id
 * @param child 子資料陣列欄位
 * @param id 子級id
 * @param childrenArray 介面返回的子級資料
 *
 * @return [tree, ...]
 * */
export function makeTree(data, pid, child, id, childrenArray) {
  const parents = data.filter(p => p[pid] === 0)
  childrenArray.forEach(item => {
    makeLongList(item, item)
  })
  dataToTree(parents, childrenArray.map(i => i.longList || [i]).flat(1))
  return parents.filter(item => item[child])

  /**
   * 遞迴向上尋找每一個子級資料對應的父級資料,並將所有父級資料放進介面返回子級資料的longList欄位
   * @param item1 介面返回的子級資料
   * @param item2 向上尋找的父級資料, 頂級父級除外,上面已經獲取到頂級資料
   *
   * */
  function makeLongList(item1, item2) {
    if (data.find(p => p[id] === item2[pid]) && data.find(p => p[id] === item2[pid])[pid]) {
      if (item1.longList) {
        item1.longList.push(data.find(p => p[id] === item2[pid]))
      } else {
        const it = JSON.parse(JSON.stringify(item1))
        item1.longList = [it, data.find(p => p[id] === item2[pid])]
      }
      // 除去頂級資料
      data.find(p => p[id] === item2[pid])[pid] && makeLongList(item1, data.find(p => p[id] === item2[pid]))
    }
  }

  function dataToTree(parents, children) {
    parents.map(p => {
      children.map((c, i) => {
        if (c[pid] === p[id]) {
          const _children = JSON.parse(JSON.stringify(children))
          _children.splice(i, 1)
          dataToTree([c], _children) // 遞迴
          if (p[child]) {
            p[child].push(c)
          } else {
            p[child] = [c]
          }
        }
      })
    })
  }
}

效果展示:

 

 

 圖中未處理的資料就是根據最後一級id向上查詢父級資料,處理後的資料是將找到的樹形資料繼續平鋪處理成元件需要的各級id組成的陣列(若業務場景固定,只需要id資料,那麼在findParentLevel方法中可以直接返回處理後的資料)。

以上便是對el-cascader設定預設值的全部內容啦,希望對你有幫助~

腳踏實地行,海闊天空飛~