开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第十二天,点击查看活动详情
题引:
公司的美工UI又来找事了,说好的按照element-ui参考画图,结果来了个tree穿梭框,好家伙,上网查了一下有个比较成熟的插件:element-tree-transfer-pro,但是安装的时候报错了,想了想还得去解决,而且需求也不是很难,那就把element-ui的el-tree组件和el-checkbox结合实现一个好了。
下图是效果:
正文:
思路:
首先说一下需求在分析思路。需求需要左边的是一个tree,选中的节点授权时需要移除自身且添加到右边,反之右边选中移除时也是一样。
布局:
通过效果图,我们直接使用el-dialog作为一个弹框载体,左边为一个el-tree,中间部分使用简单的div包裹el-button,右边是列表展示数据+el-checkbox。
代码如下:
<el-dialog class="flowAddDialog" :visible.sync="flowAddDialogVisible" title="选择人员" center width="40%" :before-close="handleClose('flowAddDialogVisible')">
<div class="transfer">
<div class="transfer-left transfer-flex">
<div>
<div>
<el-checkbox v-model="checked"></el-checkbox>
<span>全部老师</span>
</div>
<span style="color:#c0c4cc">0/98</span>
</div>
<el-input v-model="inputValue" suffix-icon="el-icon-search" placeholder="请按学校或运行商搜索"></el-input>
<el-tree ref="leftTree" :data="treeData" :props="defaultProps" default-expand-all show-checkbox @check="handleLeftTreeClick"></el-tree>
</div>
<div class="transfer-center">
<el-button type="primary" style="margin-bottom: 20px;" @click="handleAddPower">授权老师》</el-button>
<el-button type="primary" style="margin-left:0" @click="handleRemovePower">《移除老师</el-button>
</div>
<div class="transfer-right transfer-flex">
<div>
<div>
<el-checkbox v-model="checked"></el-checkbox>
<span>已选老师</span>
</div>
<span style="color:#c0c4cc">0/98</span>
</div>
<el-input v-model="inputValue" suffix-icon="el-icon-search" placeholder="请按学校或运行商搜索"></el-input>
<el-tree ref="rightTree" :data="treeCheckData" :props="{ label: 'label' }" show-checkbox @check="handleRightTreeClick"></el-tree>
</div>
</div>
<span slot="footer" class="dialog-footer">
<el-button icon="el-icon-folder-remove" type="primary" @click="handleFlowSave">保 存</el-button>
<el-button @click="handleFlowCancel">取 消</el-button>
</span>
</el-dialog>
<script>
export default{
data(){
flowAddDialogVisible: false,
treeData: [
{
label: "校长室",
id: 1,
children: [
{ id: 11, label: "李晓霞1" },
{ id: 12, label: "李晓霞2" },
{ id: 13, label: "李晓霞3" },
{ id: 14, label: "李晓霞4" },
]
},
{
id: 2, label: "总务处",
children: [
{ id: 21, label: "武清区1" },
{ id: 22, label: "武清区2" },
{ id: 23, label: "武清区3" },
{ id: 24, label: "武清区4" },
]
},
{
id: 3, label: "世界杯",
children: [
{ id: 31, label: "葡萄牙比分 3-1" },
{ id: 32, label: "巴西比分 3-2" },
{ id: 33, label: "法国比分 3-3" },
]
}
],
defaultProps: {
children: 'children',
label: 'label'
},
treeCheckData: [],
leftCheckNode: [],
rightCheckNode: [],
checked: true
}
}
</script>
<style lang="less" scoped>
.flowAddDialog {
.transfer {
display: flex;
justify-content: stretch;
align-items: center;
}
.transfer-flex{
flex: 1;
border: 1px solid #ccc;
height: 500px;
&>div:nth-child(1) {
display: flex;
justify-content: space-between;
padding: 0 10px;
height: 35px;
line-height: 35px;
font-size: 14px;
background-color: #f7f8fa;
}
}
.transfer-left {
}
.transfer-center {
width: 140px;
text-align: center;
}
.transfer-right {
}
}
</style>
基本的布局就是这样。
逻辑:
当我们授权用户时,需要把左边tree选中的过滤掉赋值给右边tree,然后重新渲染,那么我们就需要有两个变量,一个变量来保存最初的数据,一个是当前渲染的数据变量。
mounted() {
this._treeData = this.$options.data().treeData;
this._treeCheckData = this.$options.data().treeCheckData;
},
紧接着,我们需要拿到选中的节点,只需要通过el-tree的check方法即可
handleLeftTreeClick(data, node) {
this.leftCheckNode = node.checkedNodes
},
handleRightTreeClick(data, node) {
this.rightCheckNode = node.checkedNodes
},
拿到对应的节点之后,我们就需要进行一个逻辑判断
- 左tree:
当我们点击授权时,我们需要拷贝一个对象,通过forEach+filter的方法,过滤没有选中的节点重新赋值给node.children,这样就可以移除左边选中的节点,且同时加入右treehandleAddPower() { let leftTemp = Object.assign([], this.treeData) || []; let rightTemp = Object.assign([], this.treeCheckData) || []; if (this.leftCheckNode.length > 0) { this.leftCheckNode && this.leftCheckNode.forEach(item => { if (!item.children) { // 去除左边框 leftTemp.forEach(node => { node.children = node.children.filter(children => children.id !== item.id) }) // 赋值给右边框 rightTemp.push(item) } }) this.treeCheckData = rightTemp; this.treeData = leftTemp; this.leftCheckNode = []; } }, - 右ree:
当我们点击移除时,我们可以先进行边缘判断:- 是移除全部则直接重置初始化数据
- 不是的话还是按照forEach+filter方法,右tree的数据过滤需要移除的节点,把返回的数组(即未选中)重新赋值给右tree变量,同时左tree变量只需要使用初始化数据,过滤掉右tree的数据即可
handleRemovePower() { if (this.rightCheckNode.length == this.treeCheckData.length) { this.reset() } else if (this.rightCheckNode.length > 0) { let leftTemp = Object.assign([], this._treeData) || []; let unCheck = this.treeCheckData.filter(item => { let isExits = false; this.rightCheckNode.forEach(_item => { if (_item.id == item.id) isExits = true; }) if (!isExits) { return item; } }) unCheck.forEach(item => { leftTemp.forEach(node => { node.children = node.children.filter((_item, index) => { return _item.id !== item.id }) }) }) this.treeData = leftTemp; this.treeCheckData = unCheck; this.rightCheckNode = []; } }, reset() { this.treeData = this._treeData; this.treeCheckData = this._treeCheckData; }
结尾:
以上就是一个简单的demo例子。当然里面还有很多优化的地方和实现的功能,但能够完成需求就好了^_^。