目录
- vue2实现一个树型控件(支持展开树与checkbox勾选)
-
vue2实现一个树型控件(支持展开树与checkbox勾选)
TreeItem.vue
<template><div class="tree-item"><span @click="toggleExpanded" class="icon" v-show="treeNode && treeNode.children && treeNode.children.length"><spanclass="triangle":class="[ expanded ? 'triangle_down' : 'triangle_up']"></span></span><span class="icon-font icon-kaiwenjianjia-shense icon-wenjianjia"></span><span @click="toggleExpanded">{{ treeNode.deptName }}</span><input class="check-item check-style" type="checkbox" v-model="treeNode.checked" @change="handleChange(treeNode)"><div class="children" v-show="expanded"><TreeItem v-for="childNode in treeNode.children" :key="childNode.id" :tree-node="childNode" @checkItem="handleChange"></TreeItem></div></div>
</template><script>
export default {name: 'TreeItem',props: {treeNode: {type: Object,required: true}},data() {return {expanded: false,};},methods: {toggleExpanded() {this.expanded = !this.expanded;},handleChange(item) {console.log('handleChange',item, "treeNode",this.treeNode);this.setChecked(item,item.checked);this.$emit('checkItem',item)},setChecked(node, checked) {node.checked = checked;if (node.children && node.children.length > 0) {for (let child of node.children) {this.setChecked(child, checked);}}}}
};
</script><style lang="less" scoped>
.tree-item {position: relative;font-size: 14px;.check-item {position: absolute;top: 10px;right: 4px;z-index: 111;cursor: pointer;}
}
.icon {width: 16px;display: inline-block;margin-right: 4px;line-height: 20px;cursor: pointer;
}
.icon-wenjianjia {color: #ccc;margin-right: 6px;
}
.children {margin-left: 20px;
}
input[type="checkbox"] {appearance: none;border: 1px solid transparent;width: 14px;height: 14px;display: inline-block;position: relative;vertical-align: middle;cursor: pointer;background-color: #eee;
}
input[type="checkbox"]:checked {background-color: #1bc5bd;
}
input[type="checkbox"]:checked:after {content: "✔";position: absolute;left: 1px;top: -11px;font-size: 12px;color: #fff;
}
.triangle {position: relative;top: -4px;transition: 0.5s;
}
.triangle_up {display: inline-block;margin: 0px;width: 0px;height: 0px;border-left: 4px solid transparent;border-right: 4px solid transparent;border-bottom: 4px solid #ccc;
}
.triangle_down {display: inline-block;margin: 0px;width: 0px;height: 0px;border-left: 4px solid transparent;border-right: 4px solid transparent;border-top: 4px solid #ccc;
}
</style>
Tree.vue
<template><div class="select-tree-com"><TreeItemclass="tree-item" v-for="treeNode in treeData" :key="treeNode.id" :tree-node="treeNode"@checkItem="checkItem"></TreeItem></div>
</template><script>
import TreeItem from "./TreeItem"
export default {name:'SelectTreeCom',components:{TreeItem},props: {lists: {type: Array,default () {return []}},checkbox: {type: Boolean,default: false},},data() {return {treeData: [{id: 1,name: 'Node 1',deptCode:1,deptName:'Node-1',checked: false,children: [{id: 11,deptCode:11,deptName:'Node-11',parentId: 1,name: 'Node 11',checked: false,children: [{id: 111,deptName:'Node-111',deptCode:111,parentId: 11,name: 'Node 111',checked: false,children: [{id: 1111,deptName:'Node-1111',deptCode:1111,parentId: 111,name: 'Node 1111',checked: false,children: []},{id: 1112,deptName:'Node-1112',deptCode:1112,parentId: 111,name: 'Node 1112',checked: false,children: []}]},{id: 112,deptName:'Node-112',deptCode:112,parentId: 11,name: 'Node 112',checked: false,children: []}]},{id: 12,deptName:'Node-12',deptCode:12,parentId: 1,name: 'Node 12',checked: false,children: []},{id: 13,deptName:'Node-13',deptCode:13,parentId: 1,name: 'Node 13',checked: false,children: [{id: 131,deptName:'Node-131',deptCode:131,parentId: 13,name: 'Node 131',checked: false,children: [{id: 1311,deptName:'Node-1311',deptCode:1311,parentId: 131,name: 'Node 1311',checked: false,children: []},{id: 1312,deptName:'Node-1312',deptCode:1312,parentId: 131,name: 'Node 1312',checked: false,children: []}]},{id: 132,deptName:'Node-132',deptCode:132,parentId: 13,name: 'Node 132',checked: false,children: []}]},]},{id:2,deptName:'Node-2',deptCode:2,name: 'Node 2',checked: false,children: []}],checkList:[],};},watch:{lists:{handler(newV){console.log('selectTreeeCom组件lists',newV);},}},created() {},methods: {checkItem(item) {let newArr = []newArr = this.flattenNodes(item)console.log('newArr',newArr);newArr && newArr.length && newArr.forEach(item => {if ( item.checked ) {this.checkList.push(item)}});console.log('存储选中的-this.checkList',this.checkList);this.checkList && this.checkList.length && this.checkList.forEach(itemB =>{newArr.some(itemA => {if ( itemA.id === itemB.id ) {itemB.checked = itemA.checked}})})console.log('处理this.checkList',this.checkList);this.checkList = this.checkList.filter(item=>{if(item.checked) {return item;}})let uniqueArr = []uniqueArr = Array.from(new Set(this.checkList.map(item => item.id))).map(id => this.checkList.find(item => item.id === id));console.log('uniqueArr',uniqueArr);this.$emit('getCheckList', uniqueArr)},flattenNodes(data) {let nodes = [];nodes.push({id: data.id,name: data.name,checked: data.checked,deptCode: data.deptCode,deptName: data.deptName});if (data.children && data.children.length > 0) {for (let child of data.children) {nodes = nodes.concat(this.flattenNodes(child));}}return nodes;},setCheckAll(params){const allTreeData = this.treeToOneArr(this.treeData)if ( params ) {this.checkList = [...allTreeData]return this.checkList} else {this.checkList = []return this.checkList}},cancelCheckAll(){this.checkList = []},treeToOneArr(arr) {const data = JSON.parse(JSON.stringify(arr))const newData = []const hasChildren = item => {(item.children || (item.children = [])).map(v => {hasChildren(v)})delete item.childrennewData.push(item)}data.map(v => hasChildren(v))return newData},oneArrToTree(data) {const cloneData = JSON.parse(JSON.stringify(data))const result = cloneData.filter(parent => {const branchArr = cloneData.filter(child => parent.parentCode === child.parentCode)if (branchArr.length > 0) {branchArr.sort(this.compare('order'))parent.children = branchArr}return parent.parentCode === '00'})result.sort(this.compare('order'))return result},compare(property) {return function(a, b) {const value1 = a[property]const value2 = b[property]return value1 - value2}},}};
</script><style lang="less" scoped>
.select-tree-com {padding: 10px 0;
}
.tree-item {line-height: 34px;}
</style>
效果