main.js:
import VTreeSelect from "@/components/VTreeSelect";
Vue.component('VTreeSelect', VTreeSelect)
<VTreeSelect
:disable-branch-nodes="false"
:show-count="true"
v-model="queryParams.like_org_id"
:options="deptOptions"
placeholder="请选择部门"
clearable
:multiple="true"
/>
<template>
<div>
<el-popover placement="bottom-start" width="300" trigger="click" @show="popoverOpen = true" @hide="popoverOpen = false">
<div class="v_dept_tree_select_con">
<div class="v_dept_tree_select_con_t">
<el-checkbox v-model="isCheckStrictly">父子节点联动</el-checkbox>
</div>
<div class="v_dept_tree_select_con_c">
<el-tree
ref="tree"
:data="treeOptions"
:show-checkbox="multiple"
:node-key="defaultOptions.id"
:check-strictly="!isCheckStrictly"
:props="defaultOptions"
@check="treeCheck"
></el-tree>
</div>
</div>
<div slot="reference" class="v_dept_tree_select">
<div class="v_dept_tree_select_v">
<span v-if="checkedArr.length < 1" class="v_dept_tree_select_v_placeholder">{{ placeholder }}</span>
<span v-else>{{ checkedArr.map(item => item[defaultOptions.label]).join() }}</span>
</div>
<div class="v_dept_tree_select_v_icon" @mouseenter="isClearIcon = true" @mouseleave="isClearIcon = false">
<i v-if="!isClearIcon && clearable" class="el-icon-arrow-down v_dept_tree_select_v_arrow" :class="{ v_dept_tree_select_v_arrow_show: popoverOpen }"></i>
<i v-else class="el-icon-circle-close" @click.stop="handleClear"></i>
</div>
</div>
</el-popover>
</div>
</template>
<script>
export default {
model: {
prop: "value",
event: "change",
},
props: {
value: {
type: [String, Number, Array],
default: ""
},
options: {
type: Array,
default: []
},
placeholder: {
type: String,
default: ""
},
showCheckStrictly: {
type: Boolean,
default: true
},
clearable: {
type: Boolean,
default: false
},
multiple: {
type: Boolean,
default: false,
},
defaultOptions: {
type: Object,
default: () => {
return {
children: "children",
label: "label",
id: "id"
}
}
}
},
data() {
return {
isCheckStrictly: true,
popoverOpen: false,
isClearIcon: false,
treeOptions: [],
treeArr: [],
}
},
computed: {
checkedArr() {
if( this.multiple ) {
let arr = [];
this.value && this.value.forEach(id => {
let cItem = this.treeArr.filter(tItem => tItem[this.defaultOptions.id] === id)[0];
if(cItem) arr.push(cItem);
})
return arr
}else {
let cItem = this.treeArr.filter(tItem => tItem[this.defaultOptions.id] === this.value)[0];
return cItem ? [cItem] : []
}
}
},
watch: {
showCheckStrictly: {
immediate: true,
handler() {
this.isCheckStrictly = this.showCheckStrictly;
}
},
options: {
deep: true,
immediate: true,
handler() {
this.treeOptions = this.options;
this.treeArr = this.turnFormatTreeData([], this.treeOptions, 0);
}
}
},
created() {
this.init();
},
methods: {
init() {
let arr = [];
if( this.multiple ) {
arr = this.value ? this.value : [];
}else {
arr = this.value ? [this.value] : []
}
this.$nextTick(() => {
this.$refs.tree.setCheckedKeys(arr);
})
},
treeCheck(value, {checkedKeys, checkedNodes}) {
let arr = [];
if(this.isCheckStrictly) {
arr = this.turnFormatTreeData([], checkedNodes, value[this.defaultOptions.id]);
}else {
arr = checkedNodes;
}
let idArr = arr.map(item => item[this.defaultOptions.id]);
this.$emit("change", this.multiple ? idArr : idArr[0]);
},
handleClear() {
this.$emit("change", this.multiple ? [] : "");
this.$refs.tree.setCheckedKeys([]);
},
turnFormatTreeData(arr, data, pId) {
data.forEach(item => {
let cItem = JSON.parse( JSON.stringify(item) );
delete cItem[this.defaultOptions.children];
cItem.pId = pId;
arr.push(cItem);
if(item[this.defaultOptions.children] && item[this.defaultOptions.children].length > 0) {
this.turnFormatTreeData(arr, item[this.defaultOptions.children], item[this.defaultOptions.id]);
}
})
return arr
},
}
}
</script>
<style scoped lang="scss">
.v_dept_tree_select {
width: 217px;
height: 36px;
border: 1px solid #DCDFE6;
border-radius: 4px;
padding: 0 29px 0 15px;
cursor: pointer;
overflow: hidden;
position: relative;
transition: all .3s;
.v_dept_tree_select_v {
width: 100%;
color: #606266;
font-size: 14px;
white-space: nowrap;
overflow: auto;
}
.v_dept_tree_select_v_placeholder {
color: #c0c4cc;
}
.v_dept_tree_select_v_icon {
color: #C0C4CC;
position: absolute;
top: 0;
right: 9px;
.v_dept_tree_select_v_arrow {
transform: rotateZ(0deg);
transition: all .3s;
}
.v_dept_tree_select_v_arrow_show {
transform: rotateZ(-180deg);
}
}
}
.v_dept_tree_select:hover {
border-color: #C0C4CC;
}
.v_dept_tree_select_con_t {
padding-bottom: 5px;
margin-bottom: 5px;
border-bottom: 1px solid #DCDFE6;
}
.v_dept_tree_select_con_c {
max-height: 300px;
overflow: auto;
}
</style>