1、效果图
2、代码
2.1、建立一个vue文件,命名为:treeTransfer.vue, 改文件的代码如下
<template>
<!-- 自定义树形穿梭框组件、理论上左右均可选择是否为树形结构,目前固定为左侧树形、右侧无层级结构 -->
<div class="tree-transfer">
<!-- 穿梭框左侧 -->
<div class="tree-transfer-left">
<div class="title">待选项目</div>
<div class="transfer-content">
<el-input placeholder="请输入项目名称或者项目编码" v-model="filterText">
</el-input>
<!-- 左侧采用element-ui的el-tree -->
<el-tree
ref="treeLeft"
:data="dataLeft"
show-checkbox
:node-key="defaultProps.id"
:props="defaultProps"
default-expand-all
:filter-node-method="filterNode"
>
</el-tree>
</div>
</div>
<!-- 穿梭框中间按钮区域 -->
<div class="tree-transfer-middle">
<el-button
icon="el-icon-arrow-left"
@click="remove"
size="mini"
></el-button>
<el-button
icon="el-icon-arrow-right"
@click="add"
size="mini"
></el-button>
</div>
<!-- 穿梭框右侧 -->
<div class="tree-transfer-right">
<div class="title">已选项目</div>
<!-- 右侧直接放置结果 -->
<div class="transfer-content">
<el-checkbox-group class="transfer_group" v-model="rightChecked">
<el-checkbox
v-for="item in dataRight"
:label="item"
:key="item[defaultProps.id]"
>
<el-tooltip
class="item"
effect="dark"
:content="item[defaultProps.label]"
placement="bottom-start"
>
<span>{{ item[defaultProps.label] }}</span>
</el-tooltip>
</el-checkbox>
</el-checkbox-group>
</div>
</div>
</div>
</template>
<script>
export default {
// data为原始树的数据,defaultProps默认设置字段,checkedList为初始选中的list集合
props: ["datas", "defaultProps", "checkedList"],
data() {
return {
filterText: "",// 搜索名
yuansiData: [],
dataLeft: [],
dataRight: [],
rightChecked: []
};
},
watch: {
// 搜索
filterText(val) {
this.$refs.treeLeft.filter(val);
},
// 初始选中集合改变时,左侧的数据对应选中,右侧的列表加上
checkedList() {
this.$nextTick(() => {
this.checkedList.map((item, index) => {
this.$refs.treeLeft.setChecked(item[this.defaultProps.id], true);
});
this.dataRight = this.checkedList;
});
}
},
mounted() {
this.dataLeft = this.filterTreeData(this.datas);
this.yuansiData = JSON.parse(JSON.stringify(this.datas));
},
methods: {
// 树筛选
filterNode(value, data) {
if (!value) return true;
return data[this.defaultProps.label].indexOf(value) !== -1;
},
/**处理只能选择最后一级 */
filterTreeData(treeData) {
return treeData.filter(item => {
if (
item[this.defaultProps.children] &&
item[this.defaultProps.children].length > 0
) {
item.disabled = true;
item.children = this.filterTreeData(item[this.defaultProps.children]);
} else {
item[this.defaultProps.label] = `${item[this.defaultProps.label]}(${
item[this.defaultProps.pCode]
})`;
}
return item;
});
},
// 添加到右侧
add() {
// 获取所有选中的项,将最后一级选中的节点添加到右侧已选
this.dataRight = [];
let list = this.$refs.treeLeft.getCheckedNodes();
list.map((item, index) => {
if (
!item[this.defaultProps.children] ||
item[this.defaultProps.children].length == 0
) {
this.dataRight.push(item);
}
});
},
// 移除到左侧
remove() {
let rightCheckedData = JSON.parse(JSON.stringify(this.rightChecked));
rightCheckedData.map((item, index) => {
this.$refs.treeLeft.setChecked(item[this.defaultProps.id], false);
this.dataRight.map((right, rightIndex) => {
if (item[this.defaultProps.id] == right[this.defaultProps.id]) {
this.dataRight.splice(rightIndex, 1);
}
});
});
},
// 重置数据
reset() {
// 重置左侧
let list = this.$refs.treeLeft.getCheckedNodes();
list.map((item, index) => {
this.$refs.treeLeft.setChecked(item, false);
});
// 重置右侧
this.dataRight = [];
this.rightChecked = [];
},
// 返回当前选中的值
getVal() {
return this.dataRight;
}
}
};
</script>
<style>
.el-checkbox .is-disabled {
display: none;
}
.el-checkbox-group {
width: 100%;
position: relative;
overflow: auto;
overflow-x: hidden;
}
</style>
<style scoped lang="scss">
.tree-transfer {
display: flex;
min-height: 250px;
.title {
padding: 10px 20px;
border-bottom: 1px #e5e5e5 solid;
background: #f3f4f7;
}
.transfer-content {
padding: 10px;
}
.tree-transfer-left {
max-width: 640px;
min-width: 200px;
border: 1px #e5e5e5 solid;
border-radius: 4px;
max-height: 540px;
overflow-y: scroll;
}
.tree-transfer-middle {
display: flex;
justify-content: center;
align-items: center;
min-width: 120px;
}
.tree-transfer-right {
min-width: 200px;
border: 1px #e5e5e5 solid;
border-radius: 4px;
max-height: 540px;
overflow-y: scroll;
.el-checkbox {
display: block;
margin-bottom: 5px;
}
}
}
</style>
2、调用
2.1、父级引入上述组件
<template>
<el-dialog
title="绑定项目"
:visible.sync="openDialog"
width="1200px"
class="newAsset"
>
<tree-transfer
ref="insideChooseProject"
:datas="treeTransferData"
:defaultProps="defaultProps"
:checkedList="treeChecked"
></tree-transfer>
<span slot="footer" class="dialog-footer">
<el-button @click="cancel">取 消</el-button>
<el-button type="primary" @click="saveData">确 定</el-button>
</span>
</el-dialog>
</template>
<script>
data() {
return {
// 穿梭框默认
defaultProps: {
id: "deptCode",
children: "children",
label: "deptName",
pCode:"projectCode"
},
//穿梭框弹窗是否出现
openDialog: false,
// 穿梭框选中数据
treeChecked: [],
// 穿梭框数据
treeTransferData: [],
};
},
methods: {
// 触发穿梭框显示
handleEditProject() {
this.openDialog = true;
if (this.$refs.insideChooseProject) {
this.$refs.insideChooseProject.reset();
}
// 处理初始化选中的项目,若有初始选中数据则,在此添加初始选中的值
this.treeChecked =[];
},
// 弹框确认获取已选中的树的list
saveData() {
console.log(this.$refs["insideChooseProject"].getVal())
}
}
</script>
3、可以根据以上代码,改成如下效果
3.1 修改方法
// 将子组件的this.dataLeft = this.filterTreeData(this.datas);方法,替换成:this.dataLeft = this.datas;即可
// 同时,需要修改add()事件,有需要的自行即可;
希望读到这篇文章会对你有帮助~,有帮助请留下一个赞和关注(╹▽╹)
——————来自李易峰的小粉丝,凡凡同学