问题
使用 ElementUI 的 el-table 组件,默认情况下,当每页的数据过多时,浏览器就会撑开产生纵向的滚动条,这导致用户上下滚动查找表格数据时很不方便(滚到顶部看不到分页栏、滚到底部看不到搜索栏)
因此想把表格改成整个页面不产生纵向滚动条,即可视区域内能看到搜索栏+表格数据+分页栏,数据过多时,让表格自适应高度产生滚动条
思路
想实现上述需求的关键就是让表格自适应高度
首先我自己使用过的方法是通过 window.onresize
动态计算高度,然后赋值给 table 的 height 属性,但是这种方法先且不说能完全实现(如果搜索栏是可以展开收起的,这种情况没法监听window.onresize),光是使用就比较繁琐,先要封装计算方法,然后组件里还得写三步,不方便开发者使用。
js
export default function() {
return {
/**
* 基于Vue全局的封装 监听table高度变化
* @param {String} myRef 表格的ref属性,不传默认是'table'。补充:就算默认table,也要确保有ref='table'属性,不然报错
* @param {Number} customHeight 额外可调整的高度,如页码部分的高度
*/
tableHeight: (myRef = 'table', customHeight = 0) => {
this.$nextTick(() => {
// window.innerHeight 可视区域的高度
// this.$refs[myRef].$el.getBoundingClientRect().top 该元素到可视区域顶部的距离
const offsetHeight = this.$refs[myRef].$el.getBoundingClientRect().top
this.tableHeight = window.innerHeight - offsetHeight - customHeight
window.onresize = () => {
this.tableHeight = window.innerHeight - offsetHeight - customHeight
}
})
}
}
}
js
import heightUtils from '@/utils/tableHeight'
Vue.prototype.$heightUtils = heightUtils
js
data() {
return {
tableHeight: 0
}
},
mounted() {
this.$nextTick(() => {
this.$heightUtils().tableHeight('table', 120)
})
}
<template>
<table :height="tableHeight" />
</template>
以上方法固然不适用了,那么就换一种实现方式,其实网上有很多相关文章,但是我看百分之八十都是cv的,或者也有可能那些作者只考虑了最简单的表格场景,下面介绍我自己实践后的版本。
自定义指令
封装
directive/table/tableHeight.js
js
import { addResizeListener, removeResizeListener } from 'element-ui/src/utils/resize-event'
// 设置表格高度
const doResize = (el, binding, vnode) => {
// 获取表格Dom对象
const { componentInstance: $table } = vnode
// 获取调用传递过来的数据
const { value } = binding
// 没有直接终止
if (!$table) return
// 获取距底部距离(用于展示页码等信息)
const customHeight = (value && value.customHeight) || 30
// 计算列表高度并设置
const height = window.innerHeight - el.getBoundingClientRect().top - customHeight
$table.layout.setHeight(height)
$table.doLayout()
}
export default {
// 初始化设置
bind(el, binding, vnode) {
// 设置resize监听方法
el.resizeListener = () => {
doResize(el, binding, vnode)
}
// 绑定监听方法到addResizeListener
addResizeListener(window.document.body, el.resizeListener)
},
// 所在组件的 VNode 更新时设置
// 如果搜索栏是可以展开收起的,用此方法更新
update(el, binding, vnode) {
doResize(el, binding, vnode)
},
// 销毁时设置
unbind(el) {
// 移除resize监听
removeResizeListener(window.document.body, el.resizeListener)
}
}
directive/index.js
js
import tableHeight from './table/tableHeight'
const install = function(Vue) {
Vue.directive('tableHeight', tableHeight)
}
export default install
main.js
js
import directive from './directive'
Vue.use(directive)
使用
js
<template>
<table v-tableHeight="{customHeight: 76}" />
</template>
踩坑
以上代码的实现思路是网上能搜索到的(vue2/vue3都有,因为大体思路是一致的),但是其实是有坑的!
-
没有添加
overflow: auto
导致表格不能滚动,可以在table中添加style样式 -
表头没有固定,需要额外写样式 ::v-deep .el-table__header-wrapper{position: sticky; top: 0; z-index: 1;}
-
对于设置了
fixed
属性的table列,会出现问题,暂无解决方法
出现以上问题我的猜想是:
$table.layout.setHeight(height)
只是单单设置了表格的高度,但其实 table 组件中的的 height 属性传进去之后,源码做了其他处理,比如fixed的高度等。
那么是不是可以把这个自适应高度添加到一个div外壳上,让div的高度自适应,然后table添加 height: 100%
完善
directive/table/tableHeight.js
js
import { addResizeListener, removeResizeListener } from 'element-ui/src/utils/resize-event'
// 设置表格高度
const doResize = (el, binding) => {
// 获取调用传递过来的数据
const { value } = binding
// 获取距底部距离(用于展示页码等信息)
const customHeight = (value && value.customHeight) || 76
// 计算列表高度
const height = window.innerHeight - el.getBoundingClientRect().top - customHeight
// 设置高度
el.style.height = height + "px"
}
export default {
// 初始化设置
bind(el, binding) {
// 设置resize监听方法
el.resizeListener = () => {
doResize(el, binding)
}
// 绑定监听方法到addResizeListener
addResizeListener(window.document.body, el.resizeListener)
},
// 所在组件的 VNode 更新时设置
// 页面上搜索表单是可以展开收起的,当展开更多表单搜索时,表格高度没变
update(el, binding) {
doResize(el, binding)
},
// 销毁时设置
unbind(el) {
// 移除resize监听
removeResizeListener(window.document.body, el.resizeListener)
}
}
directive/index.js
js
import tableHeight from './table/tableHeight'
const install = function(Vue) {
Vue.directive('tableHeight', tableHeight)
}
export default install
main.js
js
import directive from './directive'
Vue.use(directive)
组件中
js
<template>
<div v-tableHeight="{customHeight: 76}">
<table height="100%" />
</div>
</template>
总结
大功告成,在自己项目中测了很多种情况,暂时未发现什么问题,如果jym发现我这种方式还存在问题或者有其他更便捷的方法,欢迎评论区交流!