Vue?element-ui?el-cascader?只能末級多選問題
element-ui el-cascader只能末級多選

像這樣的需求我們直接可以用css完成
/deep/.el-cascader-panel:first-child .el-checkbox{
display:none;
}擴(kuò)展實(shí)現(xiàn)element-ui中el-cascader全選功能
重所周知,element-ui中的cascader中,沒有對所有子節(jié)點(diǎn)的全選功能。
近期,公司項(xiàng)目有一個功能是,如果點(diǎn)擊了全選,則選中所有子節(jié)點(diǎn)的功能;如果在全選狀態(tài)下,取消了任意一個節(jié)點(diǎn),則移除該節(jié)點(diǎn)和全部節(jié)點(diǎn);如果在全選狀態(tài)下,又點(diǎn)擊了全選,則完成全不選的操作,即實(shí)現(xiàn)效果如下

圖1.1: 從【選中部分節(jié)點(diǎn)】(或【所有節(jié)點(diǎn)都沒有選擇】) 到【全選】的實(shí)現(xiàn)效果

圖1.2 從【已選中全部節(jié)點(diǎn)】狀態(tài)到【取消任意一個節(jié)點(diǎn)】效果圖

圖1.3 全不選效果圖(在【全選】狀態(tài)下再次點(diǎn)擊【全選】按鈕,或挨個取消已選中節(jié)點(diǎn))
實(shí)現(xiàn)思路如下
【Ⅰ】返回?cái)?shù)據(jù)格式
1. 如果是只有一層字節(jié)點(diǎn),他的數(shù)據(jù)返回格式應(yīng)是[節(jié)點(diǎn)1, 節(jié)點(diǎn)2, .....]
2. 如果含有多層節(jié)點(diǎn),他的數(shù)據(jù)返回格式應(yīng)該是[ [父節(jié)點(diǎn),子節(jié)點(diǎn),孫子節(jié)點(diǎn)...], [父節(jié)點(diǎn),子節(jié)點(diǎn),孫子節(jié)點(diǎn)...] ],這種數(shù)據(jù)返回格式,可以很清晰的看到各個節(jié)點(diǎn)所處的層次結(jié)構(gòu)
【2】全選實(shí)現(xiàn)方式
1. 全選狀態(tài):包含了所有節(jié)點(diǎn),因?yàn)閿?shù)據(jù)結(jié)構(gòu)層次的不確定,可以大致分為兩種:
第一種,單層結(jié)構(gòu),對于全選實(shí)現(xiàn)方式很簡單,通過更改綁定的數(shù)據(jù)源,加入所有節(jié)點(diǎn)即可;
第二種,多層結(jié)構(gòu),對于這種數(shù)據(jù)結(jié)構(gòu),我們采用遞歸的方式(不確定是2層,3層.還是更多),首先我們創(chuàng)建一個臨時數(shù)據(jù),用于保存根節(jié)點(diǎn)到各個子節(jié)點(diǎn)中所有節(jié)點(diǎn)的value值,對于如圖所示的11號節(jié)點(diǎn)和8號節(jié)點(diǎn),那我們應(yīng)該保存的值為[ [1, 3, 7, 11], [1, 3, 8] ]

2. 全不選狀態(tài):
- 對于這個狀態(tài)比較簡單,將數(shù)組清空即可
3. 從全選狀態(tài)到取消任意一個節(jié)點(diǎn)狀態(tài):
- 對于這個狀態(tài),刪除【全選】所對應(yīng)的節(jié)點(diǎn)和刪除本次要移除的節(jié)點(diǎn)即可
組件源碼奉上
<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: { // 級聯(lián)選擇器選項(xiàng)
type: Array,
default: []
},
is_deep: { // 是否有children,即數(shù)據(jù)深度是否為多層
type: Boolean,
required: true
},
has_all_select: { // 是否為帶有全部的選項(xiàng)
type: Boolean,
required: true
},
all_select_flag: { // '全部'選項(xiàng)的標(biāo)識
type: String | Number,
default: ''
},
value: { // 綁定的value值
type: String,
default: 'value'
},
label: { // 綁定了label值
type: String,
default: 'label'
},
filterable: { // 是否可以模糊搜索(只能選中最后一層子節(jié)點(diǎn))
type: Boolean,
default: false
}
},
mounted() {
this.options_cascader = cloneDeep(this.options) // 深拷貝傳過來的數(shù)據(jù)源,引用了lodash包
if (!this.is_deep && this.has_all_select && !this.all_select_flag) {
console.warn("當(dāng)前為單層數(shù)據(jù)且含有全部選項(xiàng),請輸入全部選項(xiàng)標(biāo)識,默認(rèn)為'',如果全部類型的標(biāo)識為''請忽略")
}
},
data() {
return {
options_cascader: [], // 所有選項(xiàng)
select_options: [], // 以選擇的節(jié)點(diǎn)
is_select_all: false, // 是否為全選
deep_option_data: [] // 緩存各個深度的value
}
},
computed: {
// 獲取配置選項(xiàng)
getProps() {
return {
multiple: true,
expandTrigger: 'hover',
emitPath: this.is_deep,
value: this.value,
label: this.label
}
},
},
methods: {
optionsChange() {
// 判斷已選中的節(jié)點(diǎn)中是否包含全部
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)
}
/**
* 如果已選擇節(jié)點(diǎn)中包含全部,且is_select_all為true時,代表移除了選項(xiàng)中除全部外的某個節(jié)點(diǎn)
* 如果已選擇節(jié)點(diǎn)中包含全部,且is_select_all為false時,代表選擇了全部節(jié)點(diǎn)
* 如果已選擇節(jié)點(diǎn)中不包含全部,且is_select_all為true時,代表取消選擇全部節(jié)點(diǎn)
* */
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)
},
// 查找全部節(jié)點(diǎn)所在的索引
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) {
// 為單層數(shù)據(jù),即沒有children
this.options_cascader.forEach(res => {
this.select_options.push(res[this.value])
})
} else {
// 多層數(shù)據(jù), 遞歸
this.getDeepOptions(this.options_cascader)
}
},
// 遞歸獲取深層數(shù)據(jù)
getDeepOptions(value) {
let arr
value.forEach(res => {
if (res.children) {
// 如果不是最后一層,則緩存當(dāng)前層次的value
this.deep_option_data.push(res[this.value])
this.getDeepOptions(res.children)
} else {
// 如果是最后一層,把最后一層的value放入級聯(lián)選擇器綁定的數(shù)組
arr = cloneDeep(this.deep_option_data)
arr.push(res[this.value])
this.select_options.push(arr)
}
})
// 每一層循環(huán)結(jié)束后,清空本層的父節(jié)點(diǎn)
this.deep_option_data.pop()
}
}
}
</script>
<style scoped>
</style>使用方法
// 多層結(jié)構(gòu),帶全部
<my-cascader
:options="options"
:is_deep="true"
:has_all_select="true"
@getOptions="getOptions">
</my-cascader>
// 單層結(jié)構(gòu),帶全部
<my-cascader
:options="options"
:is_deep="false"
:has_all_select="true"
@getOptions="getOptions">
</my-cascader>
// 注:如果不需要配置全部節(jié)點(diǎn)則直接使用element提供的cascader即可
// 本組件只考慮第一層帶有全部的情況,且全部節(jié)點(diǎn)不帶有children屬性,即只有一層,若除第一層節(jié)點(diǎn)外其他層次節(jié)點(diǎn)帶有全部選項(xiàng),則勾選本層次的上一層節(jié)點(diǎn)即可以上為個人經(jīng)驗(yàn),希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
vue elementUI 表單校驗(yàn)功能之?dāng)?shù)組多層嵌套
這篇文章主要介紹了vue elementUI 表單校驗(yàn)(數(shù)組多層嵌套)功能的實(shí)例代碼,代碼簡單易懂,非常不錯,具有一定的參考借鑒價值 ,需要的朋友可以參考下2019-06-06
vue添加錨點(diǎn),實(shí)現(xiàn)滾動頁面時錨點(diǎn)添加相應(yīng)的class操作
這篇文章主要介紹了vue添加錨點(diǎn),實(shí)現(xiàn)滾動頁面時錨點(diǎn)添加相應(yīng)的class操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-08-08
vue router使用query和params傳參的使用和區(qū)別
本篇文章主要介紹了vue router使用query和params傳參的使用和區(qū)別,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-11-11
vue-cli實(shí)現(xiàn)異步請求返回mock模擬數(shù)據(jù)
網(wǎng)上有不少使用mockjs模擬數(shù)據(jù)的文章,但基本都是本地?cái)r截請求返回?cái)?shù)據(jù),本文主要介紹了vue-cli實(shí)現(xiàn)異步請求返回mock模擬數(shù)據(jù),文中根據(jù)實(shí)例編碼詳細(xì)介紹的十分詳盡,具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-03-03
el-upload前端實(shí)現(xiàn)多文件上傳功能示例
在Vue.js中可以使用Element UI庫中的<el-upload>組件來實(shí)現(xiàn)多文件上傳的功能,這篇文章主要給大家介紹了關(guān)于el-upload前端實(shí)現(xiàn)多文件上傳功能的相關(guān)資料,需要的朋友可以參考下2024-07-07

