Vue element-ui el-cascader 隻能末級多選問題
element-ui el-cascader隻能末級多選
像這樣的需求我們直接可以用css完成
/deep/.el-cascader-panel:first-child .el-checkbox{ display:none; }
擴展實現element-ui中el-cascader全選功能
重所周知,element-ui中的cascader中,沒有對所有子節點的全選功能。
近期,公司項目有一個功能是,如果點擊瞭全選,則選中所有子節點的功能;如果在全選狀態下,取消瞭任意一個節點,則移除該節點和全部節點;如果在全選狀態下,又點擊瞭全選,則完成全不選的操作,即實現效果如下
圖1.1: 從【選中部分節點】(或【所有節點都沒有選擇】) 到【全選】的實現效果
圖1.2 從【已選中全部節點】狀態到【取消任意一個節點】效果圖
圖1.3 全不選效果圖(在【全選】狀態下再次點擊【全選】按鈕,或挨個取消已選中節點)
實現思路如下
【Ⅰ】返回數據格式
1. 如果是隻有一層字節點,他的數據返回格式應是[節點1, 節點2, …..]
2. 如果含有多層節點,他的數據返回格式應該是[ [父節點,子節點,孫子節點…], [父節點,子節點,孫子節點…] ],這種數據返回格式,可以很清晰的看到各個節點所處的層次結構
【2】全選實現方式
1. 全選狀態:包含瞭所有節點,因為數據結構層次的不確定,可以大致分為兩種:
第一種,單層結構,對於全選實現方式很簡單,通過更改綁定的數據源,加入所有節點即可;
第二種,多層結構,對於這種數據結構,我們采用遞歸的方式(不確定是2層,3層.還是更多),首先我們創建一個臨時數據,用於保存根節點到各個子節點中所有節點的value值,對於如圖所示的11號節點和8號節點,那我們應該保存的值為[ [1, 3, 7, 11], [1, 3, 8] ]
2. 全不選狀態:
- 對於這個狀態比較簡單,將數組清空即可
3. 從全選狀態到取消任意一個節點狀態:
- 對於這個狀態,刪除【全選】所對應的節點和刪除本次要移除的節點即可
組件源碼奉上
<template> <div> <el-cascader v-model="select_options" ref="cascader" :options="options_cascader" :props="getProps" :filterable="filterable" @change="optionsChange" collapse-tags clearable></el-cascader> </div> </template> <script> import cloneDeep from "lodash/cloneDeep"; export default { name: "myCascader", props: { options: { // 級聯選擇器選項 type: Array, default: [] }, is_deep: { // 是否有children,即數據深度是否為多層 type: Boolean, required: true }, has_all_select: { // 是否為帶有全部的選項 type: Boolean, required: true }, all_select_flag: { // '全部'選項的標識 type: String | Number, default: '' }, value: { // 綁定的value值 type: String, default: 'value' }, label: { // 綁定瞭label值 type: String, default: 'label' }, filterable: { // 是否可以模糊搜索(隻能選中最後一層子節點) type: Boolean, default: false } }, mounted() { this.options_cascader = cloneDeep(this.options) // 深拷貝傳過來的數據源,引用瞭lodash包 if (!this.is_deep && this.has_all_select && !this.all_select_flag) { console.warn("當前為單層數據且含有全部選項,請輸入全部選項標識,默認為'',如果全部類型的標識為''請忽略") } }, data() { return { options_cascader: [], // 所有選項 select_options: [], // 以選擇的節點 is_select_all: false, // 是否為全選 deep_option_data: [] // 緩存各個深度的value } }, computed: { // 獲取配置選項 getProps() { return { multiple: true, expandTrigger: 'hover', emitPath: this.is_deep, value: this.value, label: this.label } }, }, methods: { optionsChange() { // 判斷已選中的節點中是否包含全部 let has_all_option = false if (!this.is_deep) { has_all_option = this.select_options.includes(this.all_select_flag) } else { has_all_option = this.select_options.some(res => res.length === 1) } /** * 如果已選擇節點中包含全部,且is_select_all為true時,代表移除瞭選項中除全部外的某個節點 * 如果已選擇節點中包含全部,且is_select_all為false時,代表選擇瞭全部節點 * 如果已選擇節點中不包含全部,且is_select_all為true時,代表取消選擇全部節點 * */ if (has_all_option && this.is_select_all) { this.$refs.cascader.$refs.panel.clearCheckedNodes() this.select_options.splice(this.searchSelectAllNodeIndex(), 1) this.is_select_all = false } else if (has_all_option && !this.is_select_all) { this.is_select_all = true this.selectAll() } else if (!has_all_option && this.is_select_all) { this.is_select_all = false this.$refs.cascader.$refs.panel.clearCheckedNodes() this.select_options = [] } this.$emit('getOptions', this.select_options) }, // 查找全部節點所在的索引 searchSelectAllNodeIndex() { if (!this.is_deep) { return this.select_options.indexOf(this.all_select_flag) } else { let selectAllOptionIndex = -1 this.select_options.forEach((res, index) => { if (res.length === 1) { selectAllOptionIndex = index } }) return selectAllOptionIndex } }, // 選擇全部 selectAll() { this.select_options = [] if (!this.is_deep) { // 為單層數據,即沒有children this.options_cascader.forEach(res => { this.select_options.push(res[this.value]) }) } else { // 多層數據, 遞歸 this.getDeepOptions(this.options_cascader) } }, // 遞歸獲取深層數據 getDeepOptions(value) { let arr value.forEach(res => { if (res.children) { // 如果不是最後一層,則緩存當前層次的value this.deep_option_data.push(res[this.value]) this.getDeepOptions(res.children) } else { // 如果是最後一層,把最後一層的value放入級聯選擇器綁定的數組 arr = cloneDeep(this.deep_option_data) arr.push(res[this.value]) this.select_options.push(arr) } }) // 每一層循環結束後,清空本層的父節點 this.deep_option_data.pop() } } } </script> <style scoped> </style>
使用方法
// 多層結構,帶全部 <my-cascader :options="options" :is_deep="true" :has_all_select="true" @getOptions="getOptions"> </my-cascader> // 單層結構,帶全部 <my-cascader :options="options" :is_deep="false" :has_all_select="true" @getOptions="getOptions"> </my-cascader> // 註:如果不需要配置全部節點則直接使用element提供的cascader即可 // 本組件隻考慮第一層帶有全部的情況,且全部節點不帶有children屬性,即隻有一層,若除第一層節點外其他層次節點帶有全部選項,則勾選本層次的上一層節點即可
以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。
推薦閱讀:
- 關於element ui中el-cascader的使用方式
- vue之ele多級聯組件的使用方法詳解
- elementUI實現級聯選擇器
- elementui中的el-cascader級聯選擇器的實踐
- Vue實現省市區級聯下拉選擇框