目录 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>
效果