/*
* table-sticky.js 混入函数
* 组件需要提供parent字段,指定表格的className(字符串)
* 在页面局部组件使用此组件,如果局部组件有使用display为none,会导致header头显示不全,可使用v-if重新初始化组件
*/const mainContainer = 'el-scrollbar__wrap'; // 监听滚动的class容器
const topBarHeight = 64.1; // 顶部距离设置const rafThrottle = (fn) => {let locked = false;return function (...args) {if (locked) return;locked = true;window.requestAnimationFrame(_ => {fn.apply(this, args);locked = false;});};
}function getTopDistance (element) {var distance = element.offsetTop;while (element.offsetParent) {element = element.offsetParent;distance += element.offsetTop;}return distance;
}export default {mounted () {this.containerDom = document.getElementsByClassName(mainContainer)this.clearListener()let timer = setTimeout(() => {this.initFixedHeader()clearTimeout(timer)}, 300)window.addEventListener('resize', this.resizeChange)},deactivated () {this.clearListener()},beforeDestroy () {this.clearListener()//取消监听窗口大小window.removeEventListener('resize', this.resizeChange)},activated () {this.initFixedHeader()this.updateFixedRight()window.addEventListener('resize', this.resizeChange)let timertimer = setTimeout(() => {let container = this.containerDomif (container[0].scrollTop > 0) {container[0].scrollTop = container[0].scrollTop + 1}clearTimeout(timer)}, 1000)},methods: {activatedReload () {window.addEventListener('resize', this.resizeChange)let timer = setTimeout(() => {this.clearFixedStyle()this.initFixedHeader()}, 300)this.timerList.push(timer)},reset () {this.clearFixedStyle()},// 窗口大小变化时,初始化resizeChange () {this.headerDragend()let timer = setTimeout(() => {this.initFixedHeader()clearTimeout(timer)}, 500)},async initFixedHeader () {if (this.parent) {this.parentDom = document.getElementsByClassName(this.parent)if (this.parentDom && this.parentDom.length !== 0) {this.tableWidth = this.parentDom[0].querySelector('.el-table__header-wrapper').getBoundingClientRect().widththis.setScrollXWidth()this.tableDom = this.parentDom[0].getElementsByClassName('el-table__header-wrapper')this.scrollDom = document.querySelector('.el-scrollbar__wrap')this.scrollDom.addEventListener('scroll', this.scrollEvent)// let classNames = this.parentDom[0].getAttribute('class')// if (classNames.toLowerCase().indexOf('table_box') < 0) {// this.parentDom[0].classList.add('table_box')// }}}},// 清空监听事件clearListener () {if (this.scrollDom) {this.scrollDom.removeEventListener('scroll', this.scrollEvent)window.removeEventListener('resize', this.resizeChange)this.clearFixedStyle()this.timerList.forEach(key => {clearTimeout(key)});}},// 更新右侧固定栏updateFixedRight () {let { fixedRightHeaderDom, dom } = this.getFixedDom()if (dom.classList.contains('fixed') && this.fixedRightDom[0]) {let timer = setTimeout(() => {this.setFixedStyle({dom: fixedRightHeaderDom,left: this.fixedRightDom[0]?.getBoundingClientRect()?.left + 'px',width: getComputedStyle(this.fixedRightDom[0], null).width,scrollLeft: fixedRightHeaderDom.scrollWidth})clearTimeout(timer)}, 100)}},async headerDragend () {await this.updateWidth()await this.updateFixedRight()this.setScrollXWidth()// await this.updateHeaderHeight()},setScrollXWidth () {let timer = setTimeout(() => {if (!this.parentDom) this.parentDom = document.getElementsByClassName(this.parent)if (this.parentDom.length == 0) returnlet dom = this.parentDom[0].querySelector('.el-table__header')this.tableWidth = this.parentDom[0].querySelector('.el-table__body-wrapper').getBoundingClientRect().widththis.tableDom[0].style.width = this.tableWidth + 'px'this.updateHeaderHeight()this.headerWidth = dom.style.widthclearTimeout(timer)}, 200)},// 更新表格宽度,(拖拽改变宽度时使用)updateWidth () {if (!this.parentDom) this.parentDom = document.getElementsByClassName(this.parent)const bodyWrapperDom = this.parentDom[0].getElementsByClassName('el-table__body-wrapper')[0]const width = getComputedStyle(bodyWrapperDom, null).width//表格宽度// 给表格设置宽度。const tableParent = this.tableDomfor (let i = 0; i < tableParent.length; i++) {tableParent[i].style.width = width}},getFixedDom () {let fixedRightHeaderDom, fixedRightBox, fixedLeftHeaderDom, fixedLeftBox;let dom = this.tableDom[0]if (this.fixedLeftDom && this.fixedLeftDom[0]) {let lefarr = this.fixedLeftDom[0].childrenfixedLeftHeaderDom = lefarr[0]fixedLeftBox = lefarr[1]}if (this.fixedRightDom && this.fixedRightDom[0]) {let rightarr = this.fixedRightDom[0].childrenfixedRightHeaderDom = rightarr[0]fixedRightBox = rightarr[1]}return { fixedRightHeaderDom, fixedRightBox, fixedLeftHeaderDom, fixedLeftBox, dom }},// 更新表头高度,表头高度有可能改变updateHeaderHeight () {this.$nextTick(() => {this.tableDom = this.parentDom[0].getElementsByClassName('el-table__header-wrapper')let obj = this.tableDom[0].getBoundingClientRect()if (obj.height != this.tablexy.height) {this.tablexy.height = obj.height;let { dom } = this.getFixedDom()if (dom.classList.contains('fixed') && this.parentDom[0]) {let timer = setTimeout(() => {this.parentDom[0].getElementsByClassName('el-table__fixed-body-wrapper')[0].style.top = 0let container = this.containerDomif (container && container[0]) {container[0].scrollTop = container[0].scrollTop + 3;}clearTimeout(timer)}, 100)}}})},// 获取表格属性getTableXy () {this.tablexy = this.tableDom[0].getBoundingClientRect()this.tablexy.height = this.tableDom[0].offsetHeight// let offsetTop = getTopDistance(this.tableDom[0])// this.tablexy.height = offsetTopreturn this.tablexy},getDom () {if (!this.parentDom) {this.parentDom = document.getElementsByClassName(this.parent)}},//滚动事件scrollEvent: rafThrottle(async function (e) {this.getDom()this.tableDom = this.parentDom[0].getElementsByClassName('el-table__header-wrapper')if (this.tablexy.top == 0 || !this.tablexy.height || !this.tablexy.top) {await this.getTableXy()}this.fixedRightDom = this.parentDom[0].getElementsByClassName('el-table__fixed-right')this.fixedLeftDom = this.parentDom[0].getElementsByClassName('el-table__fixed')let { height, top, left } = this.tablexylet scrollTop = e.target.scrollToplet { fixedRightHeaderDom, fixedRightBox, fixedLeftHeaderDom, fixedLeftBox, dom } = this.getFixedDom()// table滚动到下面的时候切换列表页面, 再滚回顶部,此时top为负数,悬浮header不会回到原来的位置,故而需要重置toptop = top < 0 ? 0 : top;if (scrollTop >= height / 2 + top) {// 存在右侧固定表头if (fixedRightHeaderDom) {this.setFixedStyle({dom: fixedRightHeaderDom,left: this.fixedRightDom[0].getBoundingClientRect().left + 'px',width: getComputedStyle(this.fixedRightDom[0], null).width,scrollLeft: fixedRightHeaderDom.scrollWidth})fixedRightBox.style.top = 0 + 'px'}// 左侧固定if (fixedLeftHeaderDom) {this.setFixedStyle({dom: fixedLeftHeaderDom,left: left + 'px',width: getComputedStyle(this.fixedLeftDom[0], null).width,scrollLeft: 0})fixedLeftBox.style.top = 0 + 'px'}dom.classList.add('fixed')//加一个固定标识this.updateWidth()dom.style.position = 'fixed'dom.style.zIndex = '2000'dom.style.top = topBarHeight + 'px'dom.style.overflow = 'hidden'} else {this.clearFixedStyle()}}),//设置固定setFixedStyle (data) {let { dom, scrollLeft, width, left } = datadom.style.zIndex = '2000'dom.style.position = 'fixed'dom.style.top = topBarHeight + 'px'dom.scrollLeft = scrollLeftdom.style.width = widthdom.style.overflow = 'hidden'dom.style.left = left},// 清除header固定clearFixedStyle () {if (!this.tableDom) returnlet { height, left } = this.tablexylet { dom, fixedRightHeaderDom, fixedRightBox, fixedLeftHeaderDom, fixedLeftBox } = this.getFixedDom()if (dom.classList.contains('fixed')) {if (fixedRightHeaderDom) {fixedRightBox.style.top = height + 'px'fixedRightHeaderDom.removeAttribute("style");}if (fixedLeftHeaderDom) {fixedLeftHeaderDom.style.zIndex = '0'fixedLeftHeaderDom.style.position = 'static'fixedLeftHeaderDom.style.top = 0 + 'px'fixedLeftHeaderDom.style.left = left + 'px'fixedLeftBox.style.top = getComputedStyle(dom).height}dom.classList.remove('fixed')dom.style.position = 'static'dom.style.top = '0'dom.style.zIndex = '0'}},},computed: {__opened () {return this.$store.state.app.sidebar.opened}},watch: {__opened () {this.$nextTick(() => {this.setScrollXWidth()})}},data () {return {tablexy: {},//表格的左边宽度信息fixedRightDom: null,//右侧fixedLeftDom: null,//左侧栏固定scrollDom: null,//滚动的domparentDom: null,//表格的父元素domtableWidth: 0,timerList: [],tableDom: null,containerDom: null}},
}
参考自—— 一个好用的table底部悬浮滚动条插件 根据自己的需求调整。