image.png
如上图,这是很常见的element-ui里的table表格
有时候右侧固定操作列按钮很多,而且要根据不同的条件进行显示隐藏,当我们给操作列固定宽度的时候,就会出现明明一页表格里的按钮就1-2个,但是空白贼大,甲方不能忍,只好优化一下咯
干起来!
具体实现:
实现原理: 使用vue的指令实现 + 在对应的页面增加了些配置代码
你可以狠狠的戳这个demo 链接查看效果:
(注:可能会出现element-ui 或者Vue 链接下载一时半会加载不出来的情况,等待等待,或者刷新几次再看效果)
动图无法展示出来,所以还是访问上述例子,更直接体会效果!
笑.gif
js 改动:
directives: { // 在该模版任意元素上使用
'fit-columns': {
inserted: function () {
setTimeout(() => {
console.log(888)
adjustColumnWidth()
}, 100)
}
}
},
///....一堆其他代码
let hash = {}
// 设置操作列的宽度
function handleWidth({ table, resValue }) {
if (!table) { return }
const list = table.querySelectorAll(`col`)
const len = list.length
let gutterIndex = -1
list.forEach((el, index) => {
const isHasGutter = el.getAttribute('name').includes(`gutter`)
if (isHasGutter) {
gutterIndex = index
}
})
const idx = (gutterIndex !== -1) ? len - 2 : len - 1 // 有gutter改变的gutter的前一列,反之是最后一列
list[idx].setAttribute('width', resValue)
// 设置cell的长度
table.querySelectorAll(`td.el-table__cell > .cell`).forEach(el => {
el.style.width = `${resValue}px`
})
}
function getBtnSumWidth(ele) {
let sumWidth = 0
const arr = []
const len = ele.length
for (let i = 0; i < len; i++) {
if (ele[i].style.display !== 'none') {
const w = ele[i].clientWidth
sumWidth += w
}
arr.push(sumWidth)
}
// 加上btn之间的margin间隔
return arr
}
// 获取操作列的宽度
function getOpeColumnWidth() {
const btnDivEle = document.querySelectorAll('.specificalTable .el-table__fixed-right .btnWrap ')
let arr = []
for (let i = 0; i < btnDivEle.length; i++) {
const btnList = btnDivEle[i].children
arr = [...arr, ...getBtnSumWidth(btnList)]
}
const sum = arr.length ? Math.max(...[...new Set(arr)]) : 0
return sum
}
const PADDING = 56 // 注意这个PADDING不是固定的,根据项目的情况,调整到一个最合适的值
// 调整操作列的宽度
function adjustColumnWidth(currPage = 1) {
if (currPage === 1) {
hash = {}
}
const headerTable = document.querySelector('.specificalTable .el-table__header-wrapper > .el-table__header')
const normalTableBody = document.querySelector('.specificalTable .el-table__body-wrapper > .el-table__body')
const fixedTableBody = document.querySelector('.specificalTable .el-table__fixed-body-wrapper > .el-table__body')
const fixedRightTable = document.querySelector('.specificalTable .el-table__fixed-right')
const fixedHeaderTable = document.querySelector('.specificalTable .el-table__fixed-header-wrapper > table')
const operateColumnWidth = hash[currPage] ? hash[currPage] : getOpeColumnWidth()
const resValue = operateColumnWidth + PADDING
hash[currPage] = operateColumnWidth
fixedTableBody && (fixedTableBody.style.width = `${resValue}px`)
fixedRightTable && (fixedRightTable.style.width = `${resValue}px`)
// 设置操作列的宽度,包含col的宽度,cell的宽度,有4个table:表头,表体,fixed表头,fixed表体
handleWidth({ table: headerTable, resValue })
handleWidth({ table: normalTableBody, resValue })
handleWidth({ table: fixedHeaderTable, resValue })
handleWidth({ table: fixedTableBody, resValue })
}
上述指令做了啥事??
疑惑.jpg
我们一一解释:
- hash 的作用是为了缓存每页最大的操作列宽度作为该页操作列的宽度值
- 当currPage=1时,为啥hash重置为{}? 这是因为当页面有查询等操作时,是从第一页重新开始查,此时操作列的宽度也得动态变化,得重置重新计算
- element-table实际上有fixed属性时,表格实际上是四个table渲染 展示出来的效果,所以对四个table做了操作(关于四个table 请自行查阅相关资料了解)
- 使用querySelector时,要对该页面的table设置独特的class属性,比如这里是specificalTable 类名
- getOpeColumnWidth 获取操作列里的按钮相加的最大宽度
- handleWidth 动态设置操作列的宽度
- 当然你也可以选择将指令提取成一个文件,注册成全局指令,进行使用
再看其他代码:
mounted() {
window.addEventListener('resize', this.handleColumnWidthAndDoLayout, true)
},
beforeDestroy() {
window.removeEventListener('resize', this.handleColumnWidthAndDoLayout, true)
clearTimeout(this.timer)
this.timer = null
},
watch: {
tableData: {
handler(val) {
this.handleColumnWidthAndDoLayout()
},
deep: true
},
},
methods: {
handleColumnWidthAndDoLayout() {
const that = this
this.loading = true
this.timer = setTimeout(() => {
adjustColumnWidth()
this.loading = false
}, 800)
}
}
上述又做了啥事??
疑惑.jpg
我们一一解释:
- watch table变化,去调整操作列宽度(即页数发生变化or 页面查询)
- 页面 resize时,动态的调整操作列的宽度, 注意离开页面前,移除对应的监听
vue 文件改动
table vue里增加了4点
- table 增加class为 specificalTable
- v-fit-columns 指令
- v-loading 加载指令(element-ui高版本本身拥有的属性)
- 操作列的div增加了 class="btnWrap"
为啥要做这些操作呢?
- 增加了v-loading="loading",因为每次动态计算时操作列的宽度有短时间的闪动,增加table loading 让用户不要太关注这点
- 操作列的div增加了 class="btnWrap" , 为了让钩子函数选择器获取对应table准确,否则用单一的el.table这种,会影响其他tab 页面的table 列变化