天天看點

Vue:使用ElementUI, Cascader 級聯選擇器

需求:

  1. 多級分類
  2. 支援多選
  3. 選擇子節點需要把父節點的值也選中,用于篩選時選中父節點也能篩出子節點
  4. 分類可以無限級添加子節點
Vue:使用ElementUI, Cascader 級聯選擇器

開發

這個需求使用ElementUI, Cascader 級聯選擇器

文檔:

https://element.eleme.cn/#/zh-CN/component/cascader

參數設定

// 篩選項
options:[ {
    value: "1",
    label: "one",
    children: [
      {
        value: "1-1",
        label: "one-one"
        }
    ]
}]

// 屬性配置
props: {
    checkStrictly: true, // 父子關聯
    expandTrigger: 'hover',
    multiple: true, // 多選
    emitPath: true // true 傳回二維數組,false 傳回一維數組
}      

前後端互動問題

1、選擇了子節點誰補全父節點?

(1)前端補全,那麼Cascader需要傳回二維數組,包含完整路徑,後端傳回也需要這個完整路徑

不過,此時後端接收的值是一個一維數組,傳回資料結構溝通後和options一樣的層級結構

(2)後端補全,如果Cascader傳回一個一維數組,隻包含葉子節點,

(2.1 如果後端在存儲時自己添加父節點,資料回顯的時候會出現父節點的值,資料變得不可控

(2.2 如果後端在篩選查詢資料時自己通過子節點擷取父節點,查詢邏輯會變得複雜。

按照經驗來說,資料的查詢次數遠遠大于寫次數

為了查詢邏輯簡單,隻能在編輯時處理。

綜上,需要采用前端補全父節點的方式,需要Cascader傳回一個完整路徑的二維數組

2、資料回顯問題

最簡單的方式是後端增加一個備援參數,按照Cascader傳回的資料格式存儲

後端傳回一個options一樣的層級結構

為了減少和後端的溝通,采用了後端傳回一個options一樣的層級結構

這樣就需要遞歸的處理這個樹形層級結構,代碼如下

// 篩選項
let options = [
  {
    value: "1",
    label: "one",
    children: [
      {
        value: "1-1",
        label: "one-one",
        children: [
          {
            value: "1-1-1",
            label: "one-one-one"
          },
          {
            value: "1-1-2",
            label: "one-one-two"
          },
        ]
      },
      {
        value: "1-1-2",
        label: "one-one-two",
        children: [
          {
            value: "1-1-2-1",
            label: "one-one-two-one"
          },
          {
            value: "1-1-2-2",
            label: "one-one-two-two"
          }
        ]
      }
    ]
  }
];

// 實作深拷貝
function deepCopy(obj) {
  return JSON.parse(JSON.stringify(obj));
}

// 節點遞歸添加到數組
function treeToArray(gloablList, option, parentList) {
  // 先将該節點的值和父節點的拷貝合并
  let copyList = deepCopy(parentList);
  copyList.push(option.value);

  // 如果該節點有子節點,遞歸處理;
  // 如果沒有子節點,說明該節點是葉子節點,加入到全局list
  if (option.children) {
    for (let child of option.children) {
        treeToArray(gloablList, child, copyList);
    }
  } else {
    gloablList.push(copyList);
  }
}

// 處理清單
function treeTo2dArray(options) {
  // 定義一個全局清單,用于存放最後的值
  let gloablList = [];

  // 處理每一個節點
  for (let option of options) {
    treeToArray(gloablList, option, []);
  }

  return gloablList;
}

let ret = treeTo2dArray(options);
console.log(ret);

/**
[
  [ '1', '1-1', '1-1-1' ],
  [ '1', '1-1', '1-1-2' ],
  [ '1', '1-1-2', '1-1-2-1' ],
  [ '1', '1-1-2', '1-1-2-2' ] 
]
 */      

繼續閱讀