需要实现的需求:
1.el-table多选框选中,左边对应的树状多选框勾选
2.el-table多页全选功能:在当前页点击多页全选按钮,当前树状节点对应的el-table全部数据全部选中,并且可以回显实现增删改功能
比较啰嗦,可以直接点目录跳到指定部分内容
1.开启多选框: show-checkbox="true",参考官网api
2.禁用:每一层的树状结点的数据都要有disabled属性,并且disabled="true"
3.支持节点搜索:参考官网节点过滤部分:Element - The world's most popular Vue UI framework
4.节点名称过长显示...并且出现tooltip:在el-tree使用作用域插槽slot-scope添加el-tooltip改写el-tree原来节点
参考:el-tree文字显示不全的解决办法 / 张生荣
参考: elementui中el-tree实现复选框全部禁用_咖啡壶子的博客-CSDN博客
----------------------------------------------------------------------------分割线 ------------------------------------------
实现
template部分代码
// 部门上方搜索框
// 树状控件
// 节点过长悬浮el-tooltip显示全名
{{ node.label }}
1.开启多选:实现看template的代码
2.节点多选框禁用实现方法:
// 在生命周期中调用
created() {
this.getTreeData()
}
methods: {
// 树状结构全部禁选
disabledFn (treeData) {
// 采用遍历+递归设置disabled:true
treeData.forEach(item => {
this.$set(item, 'disabled', true)
if (item.children) {
this.disabledFn(item.children)
}
})
},
// 请求el-tree数据的方法
getTreeData () {
// xxxx 发送请求
xxapi().then(res => {
this.treeData = res.data
}).then(() => {
// 调用禁选方法 $nextTick是为了防止节点未完全渲染完毕
this.$nextTick(() => {
this.disabledFn(this.treeData)
})
})
}
}
3.节点搜索实现方法:
watch: {
filterText(val) {
this.$refs.tree.filter(val);
}
},
methods: {
filterNode(value, data) {
if (!value) return true;
return data.label.indexOf(value) !== -1;
}
},
4.节点名称过长显示... css代码
.span-ellipsis {
font-size: 14px;
width: 100%;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
使用el-tooltip看上方template代码
1.表格多选: 添加一个type="selection"的列
2.序号列: 参考自定义索引 Element - The world's most popular Vue UI framework
3.保存单行勾选的数据(选中/取消勾选):
选中-如果保存数据的数组里面没有这行数据就添加
取消勾选-如果数组里面有这行数据就删除
4.表头全选(全选/全不选):
全选-保存整页数据
全不选-删除整页数据
5.多页全选
该节点对应的表格所有页码的数据全都加入保存数据的数组里面
点击其他页码或者切换节点回到原页面勾选的数据都能回显,并且增删操作能够与保存数据的数组同步(响应式)
--------------------------------------------------------------------------------------分割线-------------------------------
实现:
template部分
// 开启表格的多选
// 序号列
// 其他列赋值
1.表格多选:看template部分代码
2.序号列实现相关方法:
methods: {
// 生成表格序号列
indexMethod (index) {
return index + (this.pageIndex - 1) * this.pageSize + 1
}
}
3.保存勾选的数据
这里的实操与分析时候的实现逻辑是有出入的
坑一:存在多页数据的情况下,不能直接使用elm的所有select方法的参数作为勾选数据
因为在type="selection"这个列里添加reserve-selection属性后,el-table会记住你勾选的行,保存在el-table组件里面的selection属性里。也就是说,添加了reserve-selection属性后,通过this.$refs['multipleTable'].selection获取到的就是此时el-table所有选中的数据,并且这个属性是只读的!如果表格数据重新渲染,el-table会通过匹配当前表格每一行的数据和selection属性保存的数组数据,如果匹配到一样的就会自动回显勾选状态。(后面也因为这个摔在坑里久久爬不起……= = )
如果只需要单页表格的勾选,应该可以直接使用elm事件的参数(参考官网api)
但是存在多页数据的情况下,不能直接使用elm的所有select方法的参数作为勾选数据(血泪教训),因为重新渲染表格this.$refs['multipleTable'].selection的数据会丢失(这也是多页全选回显实现的坑之一)
坑二:勾选表头全选(select-all)会触发select-change事件
因为所有功能已经做好了,不想写测试,感兴趣的可以自己写试试(代码能跑起来就别动它了对吧T...T)
这里爬坑爬了很久,直到看到这篇文章才解决(感谢up!!)el-table多选回显使用toggleRowSelection被动触发selection-change事件导致选择数据重复问题_正在前行的小码农的博客-CSDN博客
这里很重要!一定要多看几遍!!!
坑三:回显勾选遍历对比一定要用el-table的data数据,不然无法出现选中状态
elm提供的toggleRowSelection一定要作用于el-table的表格数据,在我的代码里就是userList(看template部分)
坑四:回显遍历时使用toggleRowSelection会出现死循环,要用setiTimeout才能解决
祭出我的经典之图
前面讲过this.$refs['muitlple'].selection是只读属性,当用toggleRowSelection改变勾选状态与this.$refs['muitlple'].selection的数据发生冲突时,elm会自动将你的toggleRowSelection改掉。
-------------------------------------------------------踩坑记录完毕----------------------------------------------------
踩完了坑,现在说怎么实现:
1.添加了reserve-selection属性一定要加row-key属性,最好以id为row-key,接受string/function
2.设立一个空数组selectList,实现最终数据的crud
2.因为选中elm会记录,所以用户手动触发select/select-all事件的时候只需要关注删除逻辑即可
select事件:
// 取消单行勾选
selectSingleRow (selection, row) {
console.log('i am select event 单行勾选/单行取消勾选', selection, row)
if (!selection.includes(row)) {
this.rowSelectFlag = true
let idx = this.selectList.findIndex(item => item.id === row.id)
if (idx !== -1) {
this.selectList.splice(idx, 1)
}
} else {
this.rowSelectFlag = true // 禁止开关,为true就可以不触发select-change事件
this.selectList.push(row)
}
}
select-change事件
// 保存单行勾选
handleSelectionChange (val) {
console.log(val, 'val') // 这里的val是这个表格所有勾选中的rows
if (val.length >= this.pageSize || val.length === 0) { // 说明曾经有全选状态 / 取消全选状态
this.rowSelectFlag = true
}
if (this.rowSelectFlag) return
this.selectList = val
},
select-all事件
通过this.$refs['multipleTable'].store.states.isAllSelected判断此时是否全选
// 取消表头全选
selectAllRows (selection) {
console.log(this.$refs['multipleTable'].store.states.isAllSelected, 'selectAllRows是否全选')
clearTimeout(this.allSelectTimer)
this.allSelectTimer = setTimeout(() => {
if (this.$refs['multipleTable'].store.states.isAllSelected) { // 全选状态
this.selectList.push(...this.userList) // 如果是全选就把表格数据全部添加进去
} else { // 取消全选状态
this.duplicateArr()
this.userList.forEach(row => {
let matchedIdx = this.selectList.findIndex(item => item.id === row.id)
if (matchedIdx !== -1) {
this.selectList.splice(matchedIdx, 1)
}
})
}
}, 0)
},
3.现在最终保存的数据selectList能够做到视图和数据保持一致了,但是回显是有问题的,需要写一个回显函数在每次请求数据之后$nextTick调用showCheck
回显函数:(因为我将数据保存在sessionStorage里面,所以我会从session里取已经勾选到的数据),回显函数一定要用setTimeout才不会出现死循环
// 表格所选行回显
showCheck () {
clearInterval(this.showCheckTimer)
this.showCheckTimer = setTimeout(() => {
this.rowSelectFlag = true
this.oldSelection = JSON.parse(window.sessionStorage.getItem('selectedUser'))
this.selectList = this.oldSelection
// console.log(this.oldSelection, 'sesson里面的')
this.userList.forEach(row => {
const matchedIndex = this.oldSelection.findIndex(item => item.id === row.id)
this.$refs['multipleTable'].toggleRowSelection(row, matchedIndex !== -1)
})
this.rowSelectFlag = false
}, 0)
},
注意:此时this.$refs['multipleTable'].selection的数据还是这一页勾选的!!!视图和数据是存在割裂的,但是翻页或者切换部门调用showCheck会将selectList的数据重新添加进el-table的selection属性中,翻页回显打印一下即可看到this.$refs['multipleTable'].selection是会不断添加的,但是不翻页elm只会保存当前页面的selection
解决了以上问题:多页全选也能顺势而为
4.多页全选:
实现逻辑就是请求el-tree节点对应的全部数据添加进selectList里面,因为根据分页进行请求的话页面表格的分页也会拉大,所以push了数据之后要修改分页重新请求
// 多页全选
selectAllPage () {
// this.queryParams.pageSize = 10000
let params = this.queryParams
params.pageSize = 10000
examPaperApi.getPaperSetting(params).then(response => {
this.selectList.push(...response.response.list)
}).then(() => {
this.queryParams.pageSize = 10
this.handleNodeClick(this.chooseNode)
})
},
5.最后selectList这个数组会出现很多重复的rows,传送数据的时候记得去重(建议采用reduce去重)
参考: reduce()方法详解之数组对象去重_reduce数组对象去重_可可爱爱的你吖的博客-CSDN博客
功能需求:
1.点击左边el-tree节点,右边表格更新对应节点的数据
2.右边表格勾选了属于左边节点的数据,左边对应节点多选框为选中状态
实现:将上面去重了之后的selectList提取每个row对象的el-tree节点id进行匹配,再用el-tree的setCheckedKeys设置勾选
// 选中右边表格用户联动左边部门勾选
deptCheckedKeys () {
let deptIds = this.selectList.map(sUser => sUser.deptIds)
deptIds = deptIds.flatMap(item => item)
let sDeptIds = deptIds.map(dept => dept.deptId)
let uniqueDeptId = (sDeptIds) => [...new Set(sDeptIds)]
if (uniqueDeptId(sDeptIds).length !== 0) {
this.$nextTick(() => {
this.$refs.tree.setCheckedKeys(uniqueDeptId(sDeptIds))
})
return uniqueDeptId(sDeptIds)
} else {
this.$nextTick(() => {
this.$refs.tree.setCheckedKeys([])
})
return []
}
}