前端通用表头吸顶类

适用场合:

        表格内容过长,致使表头无法展示

一. 类

// 表头吸顶类
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)
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值