我写的树状图因为数据量过大,所以写的是默认打开两级,子级的当点击父级才会加载,这样不会造成页面卡顿问题。
一个月前写的了,直接贴代码了。
同样,结合面向百度求知的部分。
/**
* 下拉选择树形组件,下拉框展示树形结构,提供选择某节点功能,方便其他模块调用
* 调用示例:
* <tree-select :height="400" // 下拉框中树形高度
* :width="200" // 下拉框中树形宽度
* :data="data" // 树结构的数据
* :defaultProps="defaultProps" // 树结构的props
* multiple // 多选
* :rootNodeChick="true" // 是否可以选择根节点。默认 false ture 为可选。false 为不可选
* checkStrictly // 多选时,严格遵循父子不互相关联
* :nodeKey="nodeKey" // 绑定nodeKey,默认绑定'id'
* :checkedKeys="defaultCheckedKeys" // 传递默认选中的节点key组成的数组
* :render-after-expand="false" // 是否在第一次展开某个树节点后才渲染其子节点 默认true false直接渲染
* :default-expanded-keys="idArr" // 默认展开的节点的 key 的数组
* @popoverHide="popoverHide"> // 事件有两个参数:第一个是所有选中的节点ID,第二个是所有选中的节点数据
*</tree-select>
*
* import TreeSelect from "@/utils/components/tree-select.vue";
* components: { TreeSelect },
*
*数据格式
*let obj = {
"id": "10",
"label": "琼瑶作品集",
"children": [],
};
* 清空树的选中状态。只需要将clear 从 0 累加就可以。这里是监听的数据改变状态。不为 0 则清空数据。Number类型
*/
<div class="content-body" style="padding:0">
<div style="width:820px;" class="pull-left">
<div style="width:284px; display: inline-block;margin-left: -5px">
<div class="search-box ml10 mt20" style="max-width:275px">
<input v-model.trim="filterText" type="text" placeholder="搜索" class="form- input" style="width: 260px"/><i @click="search" style="top: 3px;"></i>
</div>
<el-tree
class="common-tree mt20 ml10"
:style="style"
clearable
ref="tree"
:data="data"
:props="defaultProps"
:show-checkbox="multiple"
:node-key="nodeKey"
:check-strictly="checkStrictly"
:default-expand-all='false'
:default-expanded-keys="idArr"
:render-after-expand="true"
:expand-on-click-node="false"
:default-checked-keys="defaultCheckedKeys"
:highlight-current="true"
:filter-node-method="filterNode"
@node-click="handleNodeClick"
@check-change="handleCheckChange"></el-tree>
<!-- @check="changeCheck" -->
</div>
</div>
<div class="right-box pull-right" style="height: 600px; width:250px">
<div style="height: 46px;line-height:46px;">
<span>已选择:</span>
<span class="hand pull-right" style="color: #3171b9" @click="clearAll">清除所有</span>
</div>
<ul class="dept-box border" style="height: 400px; width:250px; padding-left: 8px">
<li class="deptItem pull-left" style="min-width:120px" v-for="(item, index) in options" :key="index">
<img src="@/../static/images/userSelector/ico_dept.png" alt="">
{{item.label}}
<img src="@/assets/img/ico8.png" alt="" class="delimg hand" @click="del(item)">
</li>
</ul>
</div>
</div>
script部分
export default {
name: "tree-select",
// props: ["clear"],
props: {
// 树结构数据
// data: {
// type: Array,
// default () {
// return [];
// }
// },
// 是否可选根节点
rootNodeChick: Boolean,
// 是否清空数据
clear: Number,
defaultProps: {
type: Object,
default () {
return {};
}
},
// 配置是否可多选
multiple: {
type: Boolean,
default () {
return false;
}
},
nodeKey: {
type: String,
default () {
return "id";
}
},
// 显示复选框情况下,是否严格遵循父子不互相关联
checkStrictly: {
type: Boolean,
default () {
return true;
}
},
// 默认选中的节点key数组
checkedKeys: {
type: Array,
default () {
return [];
}
},
width: {
type: Number,
default () {
return 275;
}
},
height: {
type: Number,
default () {
return 400;
}
},
},
data () {
return {
defaultCheckedKeys: [],
isShowSelect: true, // 是否显示树状选择器
options: [],
selectedData: [], // 选中的节点
style: "width:" + this.width + "px;" + "height:" + this.height + "px;",
selectStyle: "width:" + (this.width + 24) + "px;",
checkedIds: [],
checkedData: [],
filterText: '',
tabs: [
{
title: '选择部门',
active: true
},
],
// checkStrictly: true,
idArr: [],
data: []
};
},
mounted () {
this.getTree()
if (this.checkedKeys.length > 0) {
if (this.multiple) {
this.defaultCheckedKeys = this.checkedKeys;
this.selectedData = this.checkedKeys.map(item => {
var node = this.$refs.tree.getNode(item);
return node.label;
});
} else {
var item = this.checkedKeys[0];
this.$refs.tree.setCurrentKey(item);
var node = this.$refs.tree.getNode(item);
this.selectedData = node.label;
}
}
},
methods: {
// 父选 子全选
// 父不选 子不操作
changeCheck(currentObj, statusObj) {
let selected = statusObj.checkedKeys.indexOf(currentObj.id)
if(selected !== -1) {
this.uniteChildSame(currentObj, true)
}else {
if (!currentObj.children) {
this.uniteChildSame(currentObj, false)
}
}
},
// 统一处理子节点为相同的勾选状态
uniteChildSame (treeList, isSelected) {
this.$refs.tree.setChecked(treeList.id, isSelected)
if(treeList.children) {
for (let i = 0; i < treeList.children.length; i++) {
this.uniteChildSame(treeList.children[i], isSelected)
}
}
},
// 统一处理父节点为选中
selectedParent (currentObj) {
let currentNode = this.$refs.tree.getNode(currentObj)
if (currentNode.parent.key !== undefined) {
this.$refs.tree.setChecked(currentNode.parent, true)
this.selectedParent(currentNode.parent)
}
},
del(i) {
this.options = this.options.filter(item => item.value !== i.value)
this.$refs.tree.setChecked(i.value,false,true);
},
search() {
this.$refs.tree.filter(this.filterText)
},
filterNode(value, data) {
if (!value) return true;
return data.name.indexOf(value) !== -1;
},
loadCheckedKeys () {
if (this.checkedKeys.length > 0) {
if (this.multiple) {
this.defaultCheckedKeys = this.checkedKeys;
this.selectedData = this.checkedKeys.map(item => {
var node = this.$refs.tree.getNode(item);
return node.label;
});
} else {
var item = this.checkedKeys[0];
this.$refs.tree.setCurrentKey(item);
var node = this.$refs.tree.getNode(item);
this.selectedData = node.label;
}
}
},
popoverHide () {
if (this.multiple) {
this.checkedIds = this.$refs.tree.getCheckedKeys(); // 所有被选中的节点的 key 所组成的数组数据
this.checkedData = this.$refs.tree.getCheckedNodes(); // 所有被选中的节点所组成的数组数据
} else {
this.checkedIds = this.$refs.tree.getCurrentKey();
this.checkedData = this.$refs.tree.getCurrentNode();
}
this.$emit("popoverHide", this.checkedIds, this.checkedData);
},
// 节点被点击时的回调,返回被点击的节点数据
handleNodeClick (data, node) {
if (!this.multiple) {
let tmpMap = {};
tmpMap.value = node.key;
tmpMap.label = node.label;
this.options = [];
this.options.push(tmpMap);
this.selectedData = node.label;
}
},
// 节点选中状态发生变化时的回调
handleCheckChange () {
var checkedKeys = this.$refs.tree.getCheckedKeys(); // 所有被选中的节点的 key 所组成的数组数据
this.options = [];
if (!this.rootNodeChick) {
checkedKeys.forEach(item => {
var node = this.$refs.tree.getNode(item); // 所有被选中的节点对应的node
let tmpMap = {};
tmpMap.value = node.key;
tmpMap.label = node.label;
this.options.push(tmpMap);
});
}else {
this.options = checkedKeys.map(item => {
var node = this.$refs.tree.getNode(item); // 所有被选中的节点对应的node
let tmpMap = {};
tmpMap.value = node.key;
tmpMap.label = node.label;
return tmpMap;
});
}
this.selectedData = this.options.map(item => {
return item.label;
});
},
clearAll() {
this.options = []
this.$nextTick(() => {
this.$refs.tree.setCheckedKeys([]);
});
},
setChecked(keys, leafOnly) {
keys.forEach(item => {
var node = this.$refs.tree.getNode(item); // 所有被选中的节点对应的node
if(!node) return
let tmpMap = {};
tmpMap.value = node.key;
tmpMap.label = node.label;
this.options.push(tmpMap);
for (let i = 0; i < this.options.length; i++) {
for (let j = i + 1; j < this.options.length; j++) {
if(this.options[i].value === this.options[j].value) {
this.options.splice(j, 1)
j = j - 1
}
}
}
});
this.$nextTick(() => {
this.$refs.tree.setCheckedKeys(keys, leafOnly);
})
},
getTree() {
getDeptList().then(res => {
const map = {};
const val = [];
if(!res.data) return
res.data.forEach((item) => {
map[item.id] = item;
});
res.data.forEach((item) => {
const parent = map[item.parentId];
if (parent) {
(parent.children || (parent.children = [])).push(item);
} else {
val.push(item);
}
});
this.data = val;
})
},
},
watch: {
clear: function (n, o) {
//箭头函数 不然会发生this改变
if (n != 0) {
this.selectedData = [];
this.$nextTick(() => {
this.$refs.tree.setCheckedKeys([]);
});
}
},
selectedData: function (newData, oldData) {
this.popoverHide();
if (
newData == undefined ||
newData == null ||
newData == [] ||
newData.length == 0
)
this.$refs.tree.setCheckedKeys([]);
},
// filterText(value) {
// this.$refs.tree.filter(value)
// },
data: {
// 显示两级数据
handler() {
this.data.forEach(item => {
this.idArr.push(item.id)
})
},
deep: true
}
}
};