需求如下:
项目开发中收到需求,需要用级联结构展示,选中父级的时候子级全部勾选,且显示的是勾选中的所有值;如果只勾选子级,父不关联在内;如果勾选了所有的子节点,且父节点不选中。实现的效果如下:
选择父级的时候全选
选择子级的时候不关联父级
1.自行封装组件 创建 NewCascader.vue
<template>
<div>
<el-cascader ref="myCascader" :options="options" v-model="vop" :show-all-levels="false"
@change="handleChange"
:props="{children: 'children',label: 'title', value:'id', multiple: true,
checkStrictly: true, emitPath: false, expandTrigger:'click'}" clearable>
</el-cascader>
</div>
// :props(children:"更新为子级数组",label:"更新为数组名称",value:"更新为需要给后台传的值")其它参数请自行查阅ELement ui 文档
</template>
<script>
export default {
props: {
// 级联树数据定义
options: {
type: Array,
required: false,
default: false
},
// 级联选择器一开始绑定值,需回显
updateValue: {
type: Array,
required: false,
default: false
}
},
data() {
return {
// 选中的值
vop: [],
// 临时存放的当前选中值,用于后期的点击对比,获得当前节点值
tmpVop: [],
// 临时存放的值,用于递归函数给选中值
tmp: '',
}
},
watch: {
/** v-model绑定得值 */
vop: {
handler(n) {
// 如果数据发生变化
if (n) {
this.$emit('childByValue', this.vop)
}
},
deep: true,
immediate: true
},
/** 如果一开始就给级联选择器赋值了 */
updateValue: {
handler(n) {
if (n) {
// 拿到父级节点的值,进行回显
this.vop = this.updateValue
this.tmpVop = this.vop
}
},
deep: true,
immediate: true
}
},
methods: {
// 选中或取消选中后的赋值
checkArr(value, options, operation) {
options.map((x) => {
if (value === x.id) {
// 选中value项,并循环该节点下的其他所有子节点选中
if (x.children) {
this.checkArrNull(x.children, operation)
}
} else if (x.children) {
this.checkArr(value, x.children, operation)
}
})
},
checkArrNull(options, operation) {
options.map((x) => {
// 如果有子项,则递归,没有则选中
// 选中当前节点2判断子节点,有则继续递归
if (operation === 'add') {
this.tmp = this.tmp + ',' + x.id
} else if (operation === 'sub') {
this.tmp = this.tmp.split(',')
// shanchu zhi
this.tmp = this.removeValue(x.id, this.tmp)
this.tmp = this.tmp.join(',')
}
if (x.children) {
this.checkArrNull(x.children, operation)
}
})
},
// 获得点击change事件时点击节点的值
valueChange(tmp1, tmp2) {
for (var i = 0; i < tmp2.length; i++) {
var obj = tmp2[i]
var isExist = false
for (var j = 0; j < tmp1.length; j++) {
var aj = tmp1[j]
if (obj === aj) {
isExist = true
break
}
}
if (!isExist) {
return obj
}
}
},
// 删除数组指定的值的元素
removeValue(v, arr) {
let index = arr.indexOf(v)
if (index !== -1) {
arr.splice(index, 1)
}
return arr
},
// 数组去重
unique(arr) {
var arr2 = arr.sort()
var res = [arr2[0]]
for (var i = 1; i < arr2.length; i++) {
if (arr2[i] !== res[res.length - 1]) {
res.push(arr2[i])
}
}
return res
},
// 将options的value值按照value生成一组数组
optionsToarr(options) {
this.tmp = ''
options.map((x) => {
this.tmp = this.tmp + x.id + ','
if (x.children) {
this.optionsToarrChild(x.children)
}
})
},
optionsToarrChild(options) {
options.map((x) => {
this.tmp = this.tmp + x.id + ','
if (x.children) {
this.optionsToarrChild(x.children)
}
})
},
// change事件
handleChange(value) {
// 获得点击变化时的值,然后判断是加值还是减值。根据值去递归
let valueCh = ''
// 操作是选中还是取消
let action = ''
// 对比获得是选中还是取消操作
if ((this.vop).length > 0) {
if ((this.tmpVop).length > (this.vop).length) {
valueCh = this.valueChange(this.vop, this.tmpVop)
action = 'sub'
} else {
valueCh = this.valueChange(this.tmpVop, this.vop)
action = 'add'
}
}
if (valueCh) {
this.tmp = this.vop.join(',')
this.checkArr(valueCh, this.options, action)
// 去重
this.vop = this.unique(this.tmp.split(','))
}
// 获得options的value值一维数组,用于排序对照
this.optionsToarr(this.options)
if (this.tmp.substring(this.tmp.length - 1) === ',') {
this.tmp = this.tmp.substring(0, this.tmp.length - 1)
}
this.tmp = this.tmp.split(',')
// 排序
this.vop.sort((prev, next) => {
return this.tmp.indexOf(prev) - this.tmp.indexOf(next)
})
this.tmpVop = this.vop
}
},
created() {
// 创建时默认给tmpVop赋值
this.tmpVop = this.vop
}
}
</script>
2.页面调用
import NewCascader from '../components/NewCascader'
components: {
NewCascader
},
<NewCascader v-model="updateCheckerForm.dept" :updateValue="updateCheckerForm.dept"
v-on:childByValue="childByValueUpdate" :options="departmentList" >
</NewCascader>
/** 修改时候级联选择子传值给父 */
childByValueUpdate(childValue) {
this.updateCheckerForm.dept = childValue
console.log(this.updateCheckerForm.dept, 'this.updateCheckerForm.dept');
},
自定义数据
data () {
return {
dataList:[{
id: 'zhinan',
deptname: '指南',
children: [{
id: 'shejiyuanze',
deptname: '设计原则',
checked: true,
children: [{
id: 'yizhi',
deptname: '一致'
}, {
id: 'fankui',
deptname: '反馈'
}, {
id: 'xiaolv',
deptname: '效率'
}, {
id: 'kekong',
deptname: '可控'
}]
}, {
id: 'daohang',
deptname: '导航',
children: [{
id: 'cexiangdaohang',
deptname: '侧向导航'
}, {
id: 'dingbudaohang',
deptname: '顶部导航'
}]
}]
}, {
id: 'zujian',
deptname: '组件',
children: [{
id: 'basic',
deptname: 'Basic',
children: [{
id: 'layout',
deptname: 'Layout 布局'
}, {
id: 'color',
deptname: 'Color 色彩'
}, {
id: 'typography',
deptname: 'Typography 字体'
}, {
id: 'icon',
deptname: 'Icon 图标'
}, {
id: 'button',
deptname: 'Button 按钮'
}]
}
}],
checkerForm: {
dept:[],
},
updateCheckerForm:{
account:[]
},
}
}
},
至此就实现了级联选择组件(父关联子->子不关联父)