实现效果
原理
这里涉及到2个Dom元素,类名分别为 el-table__body-wrapper、el-table__body。
通过观察发现横向滚动条在于el-table__body-wrapper上,el-table__body则是实际的列表内容,当el-table__body宽度超出el-table__body-wrapper时就会出现横向滚动条。
因此只需要动态的修改 el-table__body-wrapper 的 height 即可实现想要的效果。
在页面发生滚动、页面大小改变以及数据源更新的时候对 el-table__body-wrapper 的 height 进行调整。
代码及使用
我们直接通过mixin混入相关代码来实现复用。
以下为 table-scroller.js
let el
let tableBodyWrapDom
let tableBodyDom
let scrollContainer
export default {
destroyed() {
// 在组件销毁时取消监听
scrollContainer.removeEventListener('scroll', this.handleScroll)
window.removeEventListener('resize', this.handleScroll)
},
methods: {
async initScroll(scrollEl = 'body') {
await this.$nextTick()
el = this.$el // 当前组件的Dom对象,避免操作到本组件之外的Dom
tableBodyWrapDom = el.querySelector('.el-table__body-wrapper')
tableBodyDom = el.querySelector('.el-table__body')
scrollContainer = document.querySelector(scrollEl) // 滚动的容器,默认为body
// this.$refs.table.handleFixedMousewheel = function() {} // 消除 FixedMousewheel 带来的问题
// 监听事件
scrollContainer.addEventListener('scroll', this.handleScroll, false)
window.addEventListener('resize', this.handleScroll, false)
},
handleScroll() {
if (!el || !tableBodyWrapDom) return
// top为dom上侧距离可视窗口顶部的值
const { top: tableBodyDomTop } = tableBodyWrapDom.getBoundingClientRect()
if (tableBodyDomTop > window.innerHeight || tableBodyWrapDom.classList.contains('is-scrolling-none')) {
// 此时列表在可视窗口的下侧不可见区域,因此不做任何修改
tableBodyWrapDom.style.height = 'unset'
tableBodyWrapDom.style.marginBottom = 'unset'
} else {
// 窗口高度 - 列表距顶部值 且 不超过自身实际值
const wrapHeight = Math.min(window.innerHeight - tableBodyDomTop, tableBodyDom.offsetHeight)
tableBodyWrapDom.style.height = wrapHeight + 'px'
// 需要用marginBottom填充,以保持列表原有高度,避免页面的纵向滚动条变化导致页面滚动的不流畅
// 可以通过注释这一行代码观察其效果差异
tableBodyWrapDom.style.marginBottom = (tableBodyDom.offsetHeight - wrapHeight) + 'px'
}
}
},
watch: {
tableData(n) {
// 当列表数据源发生变化时,再次触发
n.length && this.$nextTick(this.handleScroll)
}
}
}
使用时,只需要引入mixin,然后再合适的地方,执行 initScroller 即可
import tableScroller from '@/mixins/table-scroller'
export default {
mixins: [tableScroller],
methods: {
getDate() {
...
this.initScroll('.main-container'); // 传入滚动容器的class或id
}
}
}
评论区