适用场合:
表格内容过长,致使表头无法展示
一. 类
// 表头吸顶类
class theadFixed {
constructor (options) {
const { fixedElement, nativeElement, nativeTop, fixedStyle, fixedClass, maxHeight, tableDom } = options
this.el = nativeElement || window // 外层dom
this.dom = fixedElement // 待处理dom
this.clonedElement = null // 拷贝待处理dom,用于填补原先位置
this.tableDom = tableDom // 表格dom,用于获取宽度等
this.fixedStyle = fixedStyle || {} // 处理style
this.fixedClass = fixedClass || '' // 处理class
this.nativeTop = nativeTop || 0 // 外层dom距页面顶部距离
this.timer = null
this.preFixedStyle = {} // 记录原domstyle,用于重置
this.maxHeight = maxHeight // 阈值
this.initPreFixedStyle()
}
// 还原dom
initFn () {
this.clonedElement && this.dom.parentNode.removeChild(this.clonedElement)
if (this.fixedClass && typeof this.fixedClass === 'string') {
this.dom.classList.toggle(this.fixedClass, false)
}
for (const key in this.fixedStyle) {
this.dom.style[key] = this.preFixedStyle[key] || ''
}
this.clonedElement = null
}
// dom吸顶操作
setFn () {
if (this.clonedElement) return
this.clonedElement = this.dom.cloneNode(true) // 拷贝待处理dom
if (this.fixedClass && typeof this.fixedClass === 'string') {
this.dom.classList.toggle(this.fixedClass, true)
}
if (Object.prototype.toString.call(this.fixedStyle) === '[object Object]') {
for (const key in this.fixedStyle) {
this.dom.style[key] = this.fixedStyle[key]
}
}
// 将复制的元素置于同级,紧跟在原元素后面
this.dom.parentNode.insertBefore(this.clonedElement, this.dom.nextSibling)
}
// 主要逻辑
timedAction () {
let condition = true
if (this.dom) {
if (this.maxHeight) {
let diffHeight = 0
if (this.tableDom?.offsetHeight > this.maxHeight) {
diffHeight = this.tableDom.offsetHeight - this.maxHeight
}
condition = this.maxHeight
? this.tableDom.getBoundingClientRect().top - this.nativeTop <= 0 &&
this.tableDom.getBoundingClientRect().top - this.nativeTop + diffHeight > 0
: this.tableDom.getBoundingClientRect().top - this.nativeTop <= 0
} else {
condition = this.tableDom.getBoundingClientRect().top - this.nativeTop < 0
}
}
if (condition) {
this.setFn()
} else {
this.initFn()
}
}
// 获取dom初始化的样式
initPreFixedStyle () {
for (const key in this.dom.style) {
this.preFixedStyle[key] = this.dom.style[key]
}
}
// 重置处理样式,用于监听屏幕缩放时影响表头宽高的情况
resetStyle (style) {
for (const key in style) {
this.dom.style[key] = style[key]
this.fixedStyle[key] = style[key]
}
}
handleScrollEvent () {
this.el['addEventListener']('scroll', this.scroll, true)
}
removeScrollEvent () {
this.el['removeEventListener']('scroll', this.scroll)
}
scroll = (event) => {
// TODO:此处可考虑滚动区域的判断
if (this.timer) {
clearTimeout(this.timer)
}
this.timer = setTimeout(() => {
this.timedAction()
}, 0)
}
}
二. 操作方法
// 类实例
var scrollCase = null
// 滚动触发的实际操作函数
function scrollFn() {
scrollCase && scrollCase.removeScrollEvent()
setTimeout(() => {
// 父元素距页面顶部距离(根据有无顶栏容器决定)
const parentTop = document.querySelector('顶栏容器class')?.clientHeight || 0
// 捕获需吸顶的表头dom
const dom = document.querySelector('表头class')
// 捕获表格dom,用于计算相关样式
const tableDom = document.querySelector('表格class')
// 此处采用style控制,也可用class(fixedClass)
scrollCase = new theadFixed({
fixedElement: dom,
nativeTop: parentTop,
fixedStyle: {
position: 'fixed',
top: `${parentTop}px`,
width: `${tableDom?.offsetWidth}px`,
zIndex: 10
},
maxHeight: 420,
tableDom
})
// 触发滚动监听
scrollCase.handleScrollEvent()
// 缩放同步吸顶表头的样式
window.addEventListener('resize', resizeFn)
}, 0)
}
// 监听缩放下的样式调整操作
function resizeFn() {
// 捕获表格dom,用于计算相关样式
const tableDom = document.querySelector('表格class')
// 此处只监听了宽度的修改
scrollCase && scrollCase.resetStyle({
width: `${tableDom?.offsetWidth}px`,
})
}
三. 使用教程
以vue项目为例
mounted() {
this.scrollFn()
},
destroyed() {
this.scrollCase && this.scrollCase.removeScrollEvent()
window.removeEventListener('resize', resizeFn)
}