此处不仅表头吸顶,当表头吸顶后,分页置底
自定table-sticky.js
/* 组件需要提供parent字段,指定表格的className(字符串) */
const rafThrottle = (fn) => {
let locked = false;
return function (...args) {
if (locked) return;
locked = true;
window.requestAnimationFrame(_ => {
fn.apply(this, args);
locked = false;
});
};
}
export default {
mounted() {
this.containerDom = document.getElementsByClassName('app-main')
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 timer
timer = setTimeout(() => {
let container = this.containerDom
if (container[0].scrollTop > 0) {
container[0].scrollTop = container[0].scrollTop + 2
}
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)
}, 300)
},
async initFixedHeader() {
if (this.parent) {
// console.log('启动监听,页面:', 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().width
this.setScrollXWidth()
this.tableDom = this.parentDom[0].getElementsByClassName('el-table__header-wrapper')
this.scrollDom = document.querySelector('.app-main')
this.scrollDom.addEventListener('scroll', this.scrollEvent)
}
}
},
// 清空监听事件
clearListener() {
if (this.scrollDom) {
this.scrollDom.removeEventListener('scroll', this.scrollEvent)
window.removeEventListener('resize', this.resizeChange)
this.clearFixedStyle()
// console.log('卸载监听,页面:', this.parent)
this.timerList.forEach(key => {
clearTimeout(key)
});
}
},
// 更新右侧固定栏
updateFixedRight() {
let { fixedRightHeaderDom, dom } = this.getFixedDom()
if (dom.classList.contains('fixed')) {
let timer = setTimeout(() => {
this.setFixedStyle({
dom: fixedRightHeaderDom,
left: this.fixedRightDom[0].getBoundingClientRect().left + 'px',
width: getComputedStyle(this.fixedRightDom[0]).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) return
let dom = this.parentDom[0].querySelector('.el-table__header')
this.tableWidth = this.parentDom[0].querySelector('.el-table__body-wrapper').getBoundingClientRect().width
this.tableDom[0].style.width = this.tableWidth + 'px'
this.updateHeaderHeight()
this.headerWidth = dom.style.width
clearTimeout(timer)
}, 200)
},
// 更新表格宽度,(拖拽改变宽度时使用)
updateWidth() {
if (!this.parentDom) this.parentDom = document.getElementsByClassName(this.parent)
if (this.parentDom.length == 0) return
const bodyWrapperDom = this.parentDom[0].getElementsByClassName('el-table__body-wrapper')[0]
const cardBoxFixedDom = document.querySelector('.card-box-fixed');
const width = getComputedStyle(bodyWrapperDom).width//表格宽度
const cardBoxWidth = cardBoxFixedDom?getComputedStyle(cardBoxFixedDom).width:0//表格卡片宽度
// 给表格设置宽度。
const tableParent = this.tableDom
for (let i = 0; i < tableParent.length; i++) {
tableParent[i].style.width = width
}
// 获取分页
const pagetion = document.querySelector('.fixed-page');
// 截取width的值
let { dom } = this.getFixedDom();
let bWidth = ''
if(pagetion && dom.classList.contains('fixed')) {
bWidth = parseInt(cardBoxWidth, 10)>0?parseInt(cardBoxWidth, 10)+'px':parseInt(width, 10)+42+'px';
}else{
bWidth = 'auto'
}
if(pagetion){
pagetion.style.width = bWidth
}
},
getFixedDom() {
let fixedRightHeaderDom, fixedRightBox, fixedLeftHeaderDom, fixedLeftBox;
let dom = this.tableDom[0]
if (this.fixedLeftDom && this.fixedLeftDom[0]) {
let lefarr = this.fixedLeftDom[0].children
fixedLeftHeaderDom = lefarr[0]
fixedLeftBox = lefarr[1]
}
if (this.fixedRightDom && this.fixedRightDom[0]) {
let rightarr = this.fixedRightDom[0].children
fixedRightHeaderDom = rightarr[0]
fixedRightBox = rightarr[1]
}
return { fixedRightHeaderDom, fixedRightBox, fixedLeftHeaderDom, fixedLeftBox, dom }
},
// 更新表头高度,表头高度有可能改变
updateHeaderHeight() {
this.$nextTick(() => {
if (!this.parentDom) this.parentDom = document.getElementsByClassName(this.parent)
if (this.parentDom.length == 0) return
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')) {
let timer = setTimeout(() => {
this.parentDom[0].getElementsByClassName('el-table__fixed-body-wrapper')[0].style.top = 0
let container = this.containerDom
if (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
return this.tablexy
},
getDom() {
if (!this.parentDom) {
this.parentDom = document.getElementsByClassName(this.parent)
}
},
//滚动事件
scrollEvent: rafThrottle(async function (e) {
this.getDom();
if (!this.parentDom) this.parentDom = document.getElementsByClassName(this.parent)
if (this.parentDom.length == 0) return
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.tablexy
let scrollTop = e.target.scrollTop
let { fixedRightHeaderDom, fixedRightBox, fixedLeftHeaderDom, fixedLeftBox, dom } = this.getFixedDom()
let offsetTop = this.parentDom[0].offsetTop;
//获取滚动条
const card = document.querySelector('.card-box-fixed');
if(!card) return
if(scrollTop > offsetTop-83 && !this.initParent.includes(this.parent)){//
if (!dom.classList.contains('fixed')) {
card.style.marginBottom= '83px'
}else{
card.style.marginBottom='43px'
}
}else{
card.style.marginBottom= 0
}
//获取卡片
if (scrollTop > offsetTop) {
const pagetion = document.querySelector('.fixed-page');
// 存在右侧固定表头
if (fixedRightHeaderDom) {
this.setFixedStyle({
dom: fixedRightHeaderDom,
left: this.fixedRightDom[0].getBoundingClientRect().left + 'px',
width: getComputedStyle(this.fixedRightDom[0]).width,
scrollLeft: fixedRightHeaderDom.scrollWidth
})
fixedRightBox.style.top = 0
}
// 左侧固定
if (fixedLeftHeaderDom) {
this.setFixedStyle({
dom: fixedLeftHeaderDom,
left: left + 'px',
width: getComputedStyle(this.fixedLeftDom[0]).width,
scrollLeft: 0
})
fixedLeftBox.style.top = 0
}
dom.classList.add('fixed')//加一个固定标识
this.updateWidth()
dom.style.position = 'fixed'
dom.style.zIndex = '8'
dom.style.top = '100px'
dom.style.overflow = 'hidden'
// 获取分页
if(pagetion) pagetion.classList.add('fixed');
//获取卡片
const scrollbar = document.querySelector('.el-table-horizontal-scrollbar');
if(scrollbar && scrollbar.style.display == 'none') {
if(pagetion) pagetion.classList.add('bottom-fixed');
}else{
if(pagetion) pagetion.classList.remove('bottom-fixed');
}
//获取滚动条
// const card = document.querySelector('.card-box-fixed');
if(card) card.classList.add('fixed');
} else {
this.clearFixedStyle()
}
}),
//设置固定
setFixedStyle(data) {
let { dom, scrollLeft, width, left } = data
dom.style.zIndex = '8'
dom.style.position = 'fixed'
dom.style.top = '100px'
dom.scrollLeft = scrollLeft
dom.style.width = width
dom.style.overflow = 'hidden'
dom.style.left = left
},
// 清除header固定
clearFixedStyle() {
if (!this.tableDom) return
let { height, left } = this.tablexy
let { 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'
// 获取分页
const pagetion = document.querySelector('.fixed-page');
if(pagetion) {
pagetion.classList.remove('fixed');
pagetion.style.width = 'auto'
};
//获取滚动条
const scrollbar = document.querySelector('.el-table-horizontal-scrollbar');
if(scrollbar && scrollbar.style.display == 'none'){
if(pagetion) pagetion.classList.remove('bottom-fixed');
}
//获取卡片
const card = document.querySelector('.card-box-fixed');
if(card) card.classList.remove('fixed');
// }
},
},
computed: {
__opened() {
return this.$store.state.app.sidebar.opened
}
},
watch: {
__opened() {
this.$nextTick(() => {
this.setScrollXWidth()
})
}
},
data() {
return {
tablexy: {},//表格的左边宽度信息
fixedRightDom: null,//右侧
fixedLeftDom: null,//左侧栏固定
scrollDom: null,//滚动的dom
parentDom: null,//表格的父元素dom
tableWidth: 0,
timerList: [],
tableDom: null,
containerDom: null,
initParent:['averageOrderValue-table','averageStockStatistics-table','custUnitPriceStat-table','refundVolumeStatistics-table','salesGrowthStatistics-table','salesVolumeStatistics-table']
}
},
}
使用说明table-stickey.md
头部固定/分页固定
1.将el-table外层使用div,并定义class,注:每个div中的class名称不能相同
由于考虑到使用keep-alive,所以每个表格组件都需要加一个唯一的class值,用于获取当前唯一的表格的dom
<el-card class="parent-table">
<el-table></el-table>
</el-card>
2.引入并注入sticky-table mixins,设置当前表格组件的父元素class,即parent
```
import sticky from '@/utils/table-sticky'
export default{
mixins: [sticky],
data() {
return {
parent: 'parent-table',注:此处的parent的值必须与1中div中class相同
}
},
}
```
效果图: