自定义el-tree复选框选中状态vue elementUI
父节点展开状态,实现选中父节点只选中其第一级子节点,并且要把父节点从所有已经选中的节点中删除,即只保留子节点。父节点折叠状态,实现只选中父节点,不选中其子节点。
自定义el-tree复选框选中状态
:check-strictly属性:该属性默认false,表示严格遵循父子相互关联。父子相互关联(即选中父节点其所有子节点全部选中,取消选中父节点其子节点全部取消,且折叠、展开状态都一样)。
Attributes属性
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
check-strictly | 在显示复选框的情况下,是否严格的遵循父子不互相关联的做法,默认为 false | boolean | — | false |
node-key | 每个树节点用来作为唯一标识的属性,整棵树应该是唯一的 | String | ||
data | 展示数据 | array | ||
show-checkbox | 节点是否可被选择(展示复选框) | boolean | — | false |
props | 配置选项,具体看下表 | object |
props
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
label | 指定节点标签为节点对象的某个属性值 | string, function(data, node) | — | — |
children | 指定子树为节点对象的某个属性值 | string | — | — |
方法
Tree
内部使用了 Node 类型的对象来包装用户传入的数据,用来保存目前节点的状态。 Tree
拥有如下方法:
方法名 | 说明 | 参数 |
---|---|---|
setChecked | 通过 key / data 设置某个节点的勾选状态,使用此方法必须设置 node-key 属性 | (key/data, checked, deep) 接收三个参数,1. 勾选节点的 key 或者 data 2. boolean 类型,节点是否选中 3. boolean 类型,是否设置子节点 ,默认为 false |
Events
事件名称 | 说明 | 回调参数 |
---|---|---|
check | 当复选框被点击的时候触发 | 共两个参数,依次为:传递给 data 属性的数组中该节点所对应的对象、树目前的选中状态对象,包含 checkedNodes、checkedKeys、halfCheckedNodes、halfCheckedKeys 四个属性 |
实现el-tree复选框选中父级的同时选中父级的第一子级
(只需选中第一子级,往下的第二第三子级不需选中)
现在我们要实现选中父级的同时只选中父级的第一层子级,默认是全选中的状态即严格遵循父子相互关联,所以:check-strictly="false"无法实现此需求。所以只能使:check-strictly="true"不严格遵循父子相互关联,此时选中父级所有子级都不会被选中。要实现以上需求,需要自定义父级与子级之间相互关联的关系。
在:check-strictly="true"的前提下,写方法。首先,需要判断当前所选节点是有无子节点,如果存在子节点,然后再对其子节点进行操作。
下面代码解释:
checkedNodes,checkedKeys解释见上面表格,checkedKeys.checkedKeys是树目前的选中状态对象的数组且该数组只由node-key绑定的值组成,例(如下代码):id。例如checkedKeys.checkedKeys=["1","2"]。当前所选节点checkedNodes由当前节点对应的data数据组成,例如:checkedNodes=[id: 2, label: '一级 2',children: ...]。
若当前节点是选中状态,即checkedKeys.checkedKeys中存在checkedNodes所对应的id,即使用indexOf方法是返回checkedNodes的id在checkedKeys.checkedKeys数组中的位置。若当前节点不是选中状态,则在checkedKeys.checkedKeys数组中不存在checkedNodes的id,indexOf方法返回-1,即selected=-1。(indexOf方法的使用在下面解释)
完整代码
<el-tree :data="data" :props="defaultProps" show-checkbox node-key="id" @check="currentChange" ref="tree" :check-strictly="true">
data(){ return{ data: [{ id: 1, label: '一级 1', }, { id: 2, label: '一级 2', children: [{ id: 5, label: '二级 2-1' }, { id: 6, label: '二级 2-2' }] }], defaultProps: { children: 'children',//指定子树为data数组中的children属性值 label: 'label'//指定节点标签为data数组中的label属性值 } } }
//复选框被点击的时候触发 currentChange(checkedNodes,checkedKeys){ let selected = checkedKeys.checkedKeys.indexOf(checkedNodes.id) //当前节点为未选中状态时,selected为-1 if(checkedNodes.children!==undefined){//如果存在子级 if(selected !==-1){//如果选中 this.selectedChild(checkedNodes,true)//第一级子级选中 }else{//取消选中时 this.selectedChild(checkedNodes,false)//第一级子级取消选中 } } //获取当前所选节点的数据数组 let checkdata=this.$refs.tree.getCheckedNodes() }, selectedChild(checkedNodes,isSelected){ //checkedNodes.children是当前节点的第一级子节点checkedNodes.children.children是第二级 for(let i=0;i<checkedNodes.children.length;i++){ //setChecked方法见上面的表格,此id是el-tree属性中node-key指定的id this.$refs.tree.setChecked(checkedNodes.children[i].id,isSelected) } }
代码中indexOf方法解释:
JavaScript indexOf() 方法
定义和用法:
indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置。
语法:
stringObject.indexOf(searchvalue,fromindex)
参数 | 描述 |
---|---|
searchvalue | 必需。规定需检索的字符串值。 |
fromindex | 可选的整数参数。规定在字符串中开始检索的位置。它的合法取值是 0 到 stringObject.length - 1。如省略该参数,则将从字符串的首字符开始检索。 |
说明:
该方法将从头到尾地检索字符串 stringObject,看它是否含有子串 searchvalue。开始检索的位置在字符串的 fromindex 处或字符串的开头(没有指定 fromindex 时)。如果找到一个 searchvalue,则返回 searchvalue 的第一次出现的位置。stringObject 中的字符位置是从 0 开始的。
提示和注释:
注释:indexOf() 方法对大小写敏感!
注释:如果要检索的字符串值没有出现,则该方法返回 -1。
indexOf() 方法使用:
let selected = checkedKeys.checkedKeys.indexOf(checkedNodes.id)
实现删除父节点,只保留子节点
在上面的currentChange方法中,方法的最后获取了当前所选节点的数组,现在从这个数组中将父节点删除,只保留子节点。
//获取当前所选节点的数据数组 let checkdata=this.$refs.tree.getCheckedNodes() for(let i=0;i<checkdata.length;i++){ if(checkdata[i].children!==undefined){ checkdata.splice(i,1);//从数组中删除一个元素,第i个 } }
splice方法:
splice()
方法向/从数组添加/删除项目,并返回删除的项目。
注释:splice()
方法会改变原始数组。
语法:
array.splice(index, howmany, item1, ....., itemX)
参数值:
参数 | 描述 |
---|---|
index | 必需。整数,指定在什么位置添加/删除项目,使用负值指定从数组末尾开始的位置。 |
howmany | 可选。要删除的项目数。如果设置为 0,则不会删除任何项目。 |
item1, ..., itemX | 可选。要添加到数组中的新项目。 |
实现折叠时只选中父节点,展开时选中父节点的第一层级子节点
点击折叠展开节点的时候会触发事件。若在折叠状态选中父节点,则此时只选中父节点;此时点击展开此父节点,触发事件只选中其第一层级子节点。若在展开状态选中父节点,则此时只选中父节点的第一层级子节点;此时点击折叠此父节点,触发事件只选中父节点。
节点折叠展开状态数组存储
以上我们已经实现了只选中父节点的第一层级子节点。现在控制一下折叠展开状态。
首先,我们需要定义一个数组用来存储节点的折叠和展开状态。
data(){ return{ expandList:[] } }
然后,每次点击折叠或者展开节点的时候,将此节点的折叠展开状态存入数组。
因为我们要确定具体是哪个节点,所以要把当前节点的数据也都存进去。
如下:给el-tree添加折叠和展开节点触发的点击事件。
<el-tree :data="data" :props="defaultProps" show-checkbox node-key="id" @check="currentChange" ref="tree" :check-strictly="true" @node-expand="nodeExpand" @node-collapse="nodeCollapse">
Events
事件名称 | 说明 | 回调参数 |
---|---|---|
node-expand | 节点被展开时触发的事件 | 共三个参数,依次为:传递给 data 属性的数组中该节点所对应的对象、节点对应的 Node、节点组件本身 |
node-collapse | 节点被关闭时触发的事件 | 共三个参数,依次为:传递给 data 属性的数组中该节点所对应的对象、节点对应的 Node、节点组件本身 |
methods:{ // 展开触发的事件 nodeExpand (data) { // data是当前节点数据的JSON对象,包含id和label等信息。 // 若expandList为0直接添加该节点数据 console.log(this.expandList, 'this.expandList+++++++++') if (this.expandList.length !== 0) { // 如果expandList中存在该节点的信息, // 就判断一下expand若为false将其改为true for (let i = 0; i < this.expandList.length; i++) { if (this.expandList[i].id == data.id && this.expandList[i].expand == false) { this.expandList[i].expand = true } } } else { // JSON对象添加新的属性expand并且赋值 // 展开状态expand为true,折叠状态expand为false data.expand = true this.expandList.push(data) } }, //折叠触发的事件 nodeCollapse (data) { // 若expandList为0直接添加该节点数据 if (this.expandList.length !== 0) { // 如果expandList中存在该节点的信息, // 就判断一下expand若为true将其改为false for (let i = 0; i < this.expandList.length; i++) { if (this.expandList[i].id == data.id && this.expandList[i].expand == true) { this.expandList[i].expand = false } } } else { // JSON对象添加新的属性expand并且赋值 // 展开状态expand为true,折叠状态expand为false data.expand = false this.expandList.push(data) } } }
JSON对象添加新的属性并且赋值
方法一:
data.expand = false
方法二:
data["expand"] = false
实现展开节点只选中第一级子节点,折叠只选中父节点
以上代码实现了节点折叠展开状态的判断。
// 展开触发的事件 nodeExpand (data) { if (this.expandList.length !== 0) { for (let i = 0; i < this.expandList.length; i++) { if (this.expandList[i].id == data.id && this.expandList[i].expand == false) { this.expandList[i].expand = true } } } else { data.expand = true this.expandList.push(data) } const checkdata = this.$refs.tree.getCheckedNodes() for (let i = 0; i < this.expandList.length; i++) { for (let j = 0; j < checkdata.length; j++) { // 判断当前节点为选中状态且为展开状态且为父节点,就选中起第一级子节点,并且删除此父节点 if (this.expandList[i].id == checkdata[j].id && this.expandList[i].expand == true && checkdata[j].children !== undefined) { this.selectedChild(data, true) checkdata.splice(j, 1) } } } console.log(checkdata, 'checkdata展开+++++++++') }, //折叠触发的事件 nodeCollapse (data) { if (this.expandList.length !== 0) { for (let i = 0; i < this.expandList.length; i++) { if (this.expandList[i].id == data.id && this.expandList[i].expand == true) { this.expandList[i].expand = false } } } else { data.expand = false this.expandList.push(data) } const checkdata = this.$refs.tree.getCheckedNodes() for (let i = 0; i < this.expandList.length; i++) { for (let j = 0; j < checkdata.length; j++) { // 判断当前节点为选中状态且为展开状态且为父节点,就选中第一级子节点,并且删除此父节点 if (this.expandList[i].id == checkdata[j].id && this.expandList[i].expand == true && checkdata[j].children !== undefined) { this.selectedChild(data, true) checkdata.splice(j, 1) } } } }
父节点选择框点击事件完善
实现选中父节点的时候,展开状态只选中第一级子节点,折叠状态只选中父节点。取消选中父节点,子节点选中状态取消。
// 复选框被点击的时候触发 currentChange (checkedNodes, checkedKeys) { const selected = checkedKeys.checkedKeys.indexOf(checkedNodes.id) // 当前节点为未选中状态时,selected为-1 if (checkedNodes.children !== undefined) { // 如果存在子级 if (selected !== -1) { // 如果选中 for (let i = 0; i < this.expandList.length; i++) { if (this.expandList[i].id == checkedNodes.id && this.expandList[i].expand == true) { this.selectedChild(checkedNodes, true)// 第一级子级选中 } else { this.selectedChild(checkedNodes, false)// 第一级子级取消选中 } } } else { // 取消选中时 this.selectedChild(checkedNodes, false)// 第一级子级取消选中 } } // 获取当前所选节点的数据数组 const checkdata = this.$refs.tree.getCheckedNodes() // 父节点若是展开状态,删除父节点 for (let i = 0; i < this.expandList.length; i++) { for (let j = 0; j < checkdata.length; j++) { if (this.expandList[i].id == checkdata[j].id && this.expandList[i].expand == true && checkdata[j].children !== undefined) { checkdata.splice(j, 1) } } } console.log(checkdata, 'checkdata选择+++++++++') },
完整代码
<template> <div> <el-tree :data="data" :props="defaultProps" show-checkbox node-key="id" @check="currentChange" ref="tree" :check-strictly="true" @node-expand="nodeExpand" @node-collapse="nodeCollapse"> </el-tree> </div> </template> <script> export default { data () { return { expandList: [], data: [{ id: 1, label: '一级 1' }, { id: 2, label: '一级 2', children: [{ id: 5, label: '二级 2-1', children: [{ id: 7, label: '三级 2-1' }, { id: 8, label: '三级 2-2' }] }, { id: 6, label: '二级 2-2' }] }], defaultProps: { children: 'children', // 指定子树为data数组中的children属性值 label: 'label'// 指定节点标签为data数组中的label属性值 }, } }, methods: { // 复选框被点击的时候触发 currentChange (checkedNodes, checkedKeys) { const selected = checkedKeys.checkedKeys.indexOf(checkedNodes.id) // 当前节点为未选中状态时,selected为-1 if (checkedNodes.children !== undefined) { // 如果存在子级 if (selected !== -1) { // 如果选中 for (let i = 0; i < this.expandList.length; i++) { if (this.expandList[i].id == checkedNodes.id && this.expandList[i].expand == true) { this.selectedChild(checkedNodes, true)// 第一级子级选中 } else { this.selectedChild(checkedNodes, false)// 第一级子级取消选中 } } } else { // 取消选中时 this.selectedChild(checkedNodes, false)// 第一级子级取消选中 } } // 获取当前所选节点的数据数组 const checkdata = this.$refs.tree.getCheckedNodes() // 父节点若是展开状态,删除父节点 for (let i = 0; i < this.expandList.length; i++) { for (let j = 0; j < checkdata.length; j++) { if (this.expandList[i].id == checkdata[j].id && this.expandList[i].expand == true && checkdata[j].children !== undefined) { checkdata.splice(j, 1) } } } console.log(checkdata, 'checkdata选择+++++++++') }, selectedChild (checkedNodes, isSelected) { // checkedNodes.children是当前节点的第一级子节点checkedNodes.children.children是第二级 console.log(checkedNodes, 'checkedNodes++++++') for (let i = 0; i < checkedNodes.children.length; i++) { // setChecked方法见上面的表格,此id是el-tree属性中node-key指定的id this.$refs.tree.setChecked(checkedNodes.children[i].id, isSelected) console.log(checkedNodes, '子节点选择+++++++++') } }, // 展开触发的事件 nodeExpand (data) { // data是当前节点数据的JSON对象,包含id和label等信息。 // 若expandList为0直接添加该节点数据 if (this.expandList.length !== 0) { // 如果expandList中存在该节点的信息, // 就判断一下expand若为false将其改为true for (let i = 0; i < this.expandList.length; i++) { if (this.expandList[i].id == data.id && this.expandList[i].expand == false) { this.expandList[i].expand = true } } } else { // JSON对象添加新的属性expand并且赋值 // 展开状态expand为true,折叠状态expand为false data.expand = true this.expandList.push(data) } const checkdata = this.$refs.tree.getCheckedNodes() for (let i = 0; i < this.expandList.length; i++) { for (let j = 0; j < checkdata.length; j++) { // 判断当前节点为选中状态且为展开状态且为父节点,就选中第一级子节点,并且删除此父节点 if (this.expandList[i].id == checkdata[j].id && this.expandList[i].expand == true && checkdata[j].children !== undefined) { console.log(data, 'data+++++++') this.selectedChild(data, true) // checkdata.splice(j, 1) } } } console.log(checkdata, 'checkdata展开+++++++++') }, nodeCollapse (data) { // 若expandList为0直接添加该节点数据 if (this.expandList.length !== 0) { // 如果expandList中存在该节点的信息, // 就判断一下expand若为true将其改为false for (let i = 0; i < this.expandList.length; i++) { if (this.expandList[i].id == data.id && this.expandList[i].expand == true) { this.expandList[i].expand = false } } } else { // JSON对象添加新的属性expand并且赋值 // 展开状态expand为true,折叠状态expand为false data.expand = false this.expandList.push(data) } const checkdata = this.$refs.tree.getCheckedNodes() for (let i = 0; i < this.expandList.length; i++) { for (let j = 0; j < checkdata.length; j++) { // 判断当前节点为选中状态且为折叠状态且为父节点,就取消选中起第一级子节点 if (this.expandList[i].id == checkdata[j].id && this.expandList[i].expand == false && checkdata[j].children !== undefined) { this.selectedChild(data, false) } } } console.log(checkdata, 'checkdata+++折叠++++++') } } } </script> <style scoped lang="less"> </style>
更多推荐
所有评论(0)