目录
vue2实现一个树型控件(支持展开树与checkbox勾选)
vue2实现一个树型控件(支持展开树与checkbox勾选)
TreeItem.vue
< template>
< div class = "tree-item" >
< span @click= "toggleExpanded" class = "icon" v- show= "treeNode && treeNode.children && treeNode.children.length" >
< span
class = "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" >
< TreeItem
class = "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. children
newData. 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>
效果