现在有这样的一个需求,需要选中父,子全部勾选,且显示的是勾选中的所有值;如果只勾选子,父不关联在内;如果勾选了所有的子节点,且父节点不选中,默认每个节点下都有人,所以,勾选所有的子,不代表就是选中了父下的直接人员。实现的效果动图如下:
1、创建一个vue文件(包含新增,修改是的回显),如myCascader.vue
<!--
改装后的级联选择器,父关联子,子不关联父
-->
<template>
<div>
<el-cascader
ref="myCascader"
:options="options"
v-model="vop"
:show-all-levels="false"
@change="handleChange"
:props="{children: 'children',label: 'deptname',
value:'id', multiple: true, checkStrictly: true,
emitPath: false, expandTrigger:'click'
}"
clearable></el-cascader>
<!-- <input type="text" v-model="vop" size="100" name="rex" style="margin-top:200px">-->
</div>
</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) {
console.log(options,'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 myCascader from '@/components/myCascader'
export default {
components: {userTree,myCascader },
},
新增的时候,不需要回显,如下使用:
<myCascader
v-model="checkerForm.dept"
:updateValue="checkerForm.dept"
v-on:childByValue="childByValue"
:options="deptList1">
</myCascader>
methods: {
/** 新增时候级联选择器子传值给父 */
childByValue(childValue){
this.checkerForm.dept = childValue
},
},
注:checkerForm.dept为自定义新增的时候,级联选择器选中的值;
deptList1为级联选择的数据
修改的时候,会有回显的问题,这时候会多一步
<myCascader
v-model="updateCheckerForm.dept"
:updateValue="updateCheckerForm.dept"
v-on:childByValue="childByValueUpdate"
:options="deptList1">
</myCascader>
/** 修改时候级联选择子传值给父 */
childByValueUpdate(childValue){
this.updateCheckerForm.dept = childValue
},
注::updateValue="updateCheckerForm.dept" ,修改时的默认数据,进行回显
新增和修改也可以公用一个组件,加一个三目判断即可。这里为了方便理解,故而分开了。
补充:
// 数据定义
data () {
return {
deptList1:[{
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 按钮'
}]
}, {
id: 'form',
deptname: 'Form',
children: [{
id: 'radio',
deptname: 'Radio 单选框'
}, {
id: 'checkbox',
deptname: 'Checkbox 多选框'
}, {
id: 'input',
deptname: 'Input 输入框'
}, {
id: 'input-number',
deptname: 'InputNumber 计数器'
}, {
id: 'select',
deptname: 'Select 选择器'
}, {
id: 'cascader',
deptname: 'Cascader 级联选择器'
}, {
id: 'switch',
deptname: 'Switch 开关'
}, {
id: 'slider',
deptname: 'Slider 滑块'
}, {
id: 'time-picker',
deptname: 'TimePicker 时间选择器'
}, {
id: 'date-picker',
deptname: 'DatePicker 日期选择器'
}, {
id: 'datetime-picker',
deptname: 'DateTimePicker 日期时间选择器'
}, {
id: 'upload',
deptname: 'Upload 上传'
}, {
id: 'rate',
deptname: 'Rate 评分'
}, {
id: 'form1',
deptname: 'Form 表单'
}]
}, {
id: 'data',
label: 'Data',
children: [{
id: 'table',
deptname: 'Table 表格'
}, {
id: 'tag',
deptname: 'Tag 标签'
}, {
id: 'progress',
deptname: 'Progress 进度条'
}, {
id: 'tree',
deptname: 'Tree 树形控件'
}, {
id: 'pagination',
deptname: 'Pagination 分页'
}, {
id: 'badge',
deptname: 'Badge 标记'
}]
}, {
id: 'notice',
deptname: 'Notice',
children: [{
id: 'alert',
deptname: 'Alert 警告'
}, {
id: 'loading',
deptname: 'Loading 加载'
}, {
id: 'message',
deptname: 'Message 消息提示'
}, {
id: 'message-box',
deptname: 'MessageBox 弹框'
}, {
id: 'notification',
deptname: 'Notification 通知'
}]
}, {
id: 'navigation',
deptname: 'Navigation',
children: [{
id: 'menu',
deptname: 'NavMenu 导航菜单'
}, {
id: 'tabs',
deptname: 'Tabs 标签页'
}, {
id: 'breadcrumb',
deptname: 'Breadcrumb 面包屑'
}, {
id: 'dropdown',
deptname: 'Dropdown 下拉菜单'
}, {
id: 'steps',
deptname: 'Steps 步骤条'
}]
}, {
id: 'others',
deptname: 'Others',
children: [{
id: 'dialog',
deptname: 'Dialog 对话框'
}, {
id: 'tooltip',
deptname: 'Tooltip 文字提示'
}, {
id: 'popover',
deptname: 'Popover 弹出框'
}, {
id: 'card',
deptname: 'Card 卡片'
}, {
id: 'carousel',
deptname: 'Carousel 走马灯'
}, {
id: 'collapse',
deptname: 'Collapse 折叠面板'
}]
}]
}, {
id: 'ziyuan',
deptname: '资源',
children: [{
id: 'axure',
deptname: 'Axure Components'
}, {
id: 'sketch',
deptname: 'Sketch Templates'
}, {
id: 'jiaohu',
deptname: '组件交互文档'
}]
}],
checkerForm: {
dept:[],
},
updateCheckerForm:{
account:[]
},
}
}
},