主要功能点是:
①勾选左侧数据,同时将其父级一起携带到右侧数据
②左侧数据取消勾选,右侧数据对应移除;右侧数据点击移除按钮,右侧数据移除且左侧对应数据取消勾选
③其他列表数据绑定过的,将置灰无法点击
一:代码实现:
1.html:
<el-form-item label="项目费用类别选择" class="type-choose">
<div class="left-tree">
<div class="dialog-header">项目费用类别</div>
<el-input size="mini" placeholder="输入关键字进行过滤" v-model="filterText"> </el-input>
<el-tree
:data="fromData"
show-checkbox
node-key="id"
ref="leftTree"
:default-checked-keys="[]"
:default-expanded-keys="defaultExpandKeys"
:props="{
children: 'children',
label: 'assisTypeName',
disabled: disabledFun,
}"
:filter-node-method="filterNode"
@check="checkChange"
>
</el-tree>
</div>
<div class="right-tree">
<div class="dialog-header">
已选项目费用类别
<el-button class="fr dialog-remove-all" size="mini" type="text" @click="removeChooseTree"
>清空</el-button
>
</div>
<el-tree
:data="toData"
node-key="id"
ref="rightTree"
default-expand-all
:default-expanded-keys="[]"
:default-checked-keys="[]"
:render-content="renderContent"
:props="{
children: 'children',
label: 'assisTypeName',
}"
>
</el-tree>
</div>
</el-form-item>
2.data:
fromData: [],
toData: [],
defaultExpandKeys:[]
3.watch:
filterText(val) {
this.$refs.leftTree.filter(val);
},
4.methods:
1.勾选左侧数据,同时将其父级一起携带到右侧数据
checkChange(node, obj) {
let { checkedKeys, halfCheckedKeys } = obj
this.toData = deepCopy(this.fromData)
this.removeNoCheck(this.toData, checkedKeys.concat(halfCheckedKeys))
},
removeNoCheck(data, keys) {
for (let index = data.length - 1; index >= 0; index--) {
let item = data[index];
if (!keys.includes(item.id)) {
data.splice(index, 1)
}
if (item.children && item.children.length) this.removeNoCheck(item.children, keys)
}
},
2.左侧数据取消勾选,右侧数据对应移除;右侧数据点击移除按钮,右侧数据移除且左侧对应数据取消勾选
renderContent(h, { node, data, store }) {
return (
<span class="custom-tree-node">
<span>{node.label}</span>
<span>
<el-button style='color:red' size="mini" type="text" on-click={() => this.removeDom({ node, data })}>移除</el-button>
</span>
</span>);
},
// 删除节点数据方法
removeDom({ node, data }) {
this.$refs.leftTree.setChecked(data.id, false, true)
const parent = node.parent
const children = parent.data.children || parent.data
const index = children.findIndex(d => d.id === data.id)
children.splice(index, 1)
// 子级移除,判断父级们是否没有了子级,若没有,移除对应父级。若有,则保留父级
data.parentId && this.ifParentNoChildCheck({ id: data.parentId, data: this.toData })
},
ifParentNoChildCheck({ id, data }) {
for (let index = data.length - 1; index >= 0; index--) {
const item = data[index];
// 无子级直接移除
if (item.id === id && (!item.children || !item.children.length)) {
data.splice(index, 1)
// 判断移除的子级的父级是否还有子级,若没有,移除对应父级。若有,则保留父级
item.parentId && this.ifParentNoChildCheck({ id: item.parentId, data: this.toData })
} else if (item.id !== id && item.children && item.children.length) {
// 不是匹配父级id,有子级,继续往下遍历
this.ifParentNoChildCheck({ id, data: item.children })
}
}
},
3.其他列表数据绑定过的,将置灰无法点击
// 点击新增时
let allChooseIds = Array.from(new Set(this.tableData.map(item => item.chooseItemsIds).flat()))
this.addDisabled(this.fromData, allChooseIds)
addDisabled(data, bindSysDeprtIds) {
data.forEach((item) => {
if (item.level < 2) this.defaultExpandKeys.push(item.id)
// 编辑
if (bindSysDeprtIds) {
// 已绑定的项目费用类别禁止点击
if (bindSysDeprtIds.includes(item.id)) item.disabled = true;
else item.disabled = false;
} else {
// 新增
if (bindSysDeprtIds.includes(item.id)) {
item.disabled = true;
}
else item.disabled = false;
}
if (item.children) this.addDisabled(item.children, bindSysDeprtIds);
});
},
// 子级如果全部已绑定(已禁用),则对应父级也禁用
disabledFun(data, node) {
if (node.childNodes && node.childNodes.length) {
let alldis = true
for (let index = 0; index < node.childNodes.length; index++) {
const item = node.childNodes[index];
if (!item.disabled) alldis = false
}
if (alldis) return true
}
return data.disabled
},
4.搜索过滤
filterNode(value, data) {
if (!value) return true;
return data.assisTypeName.indexOf(value) !== -1;
},