element-table 悬浮header


/* 
* 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 timer
    timer = setTimeout(() => {
      let container = this.containerDom
      if (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().width
          this.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) 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)
      const bodyWrapperDom = this.parentDom[0].getElementsByClassName('el-table__body-wrapper')[0]
      const width = getComputedStyle(bodyWrapperDom, null).width//表格宽度
      // 给表格设置宽度。
      const tableParent = this.tableDom
      for (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].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(() => {
        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 = 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
      // let offsetTop = getTopDistance(this.tableDom[0])
      // this.tablexy.height = offsetTop
      return 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.tablexy
      let scrollTop = e.target.scrollTop
      let { fixedRightHeaderDom, fixedRightBox, fixedLeftHeaderDom, fixedLeftBox, dom } = this.getFixedDom()
      // table滚动到下面的时候切换列表页面, 再滚回顶部,此时top为负数,悬浮header不会回到原来的位置,故而需要重置top
      top = 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 } = data
      dom.style.zIndex = '2000'
      dom.style.position = 'fixed'
      dom.style.top = topBarHeight + 'px'
      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'
      }
    },
  },
  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
    }
  },
}

参考自—— 一个好用的table底部悬浮滚动条插件 根据自己的需求调整。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
element-plus-table-dragable是一个基于Vue.jsElement Plus实现的表格拖拽排序和列宽度调整的组件,用户可以使用鼠标拖拽表格的列头来改变列的宽度,也可以使用鼠标拖拽表格的行来实现表格行的排序。 该组件的开发灵感来源于Element Plus组件库的el-table组件,但为了提高用户的使用体验和便捷性,element-plus-table-dragable通过添加拖拽排序和列宽度调整功能,使用户能够更加自由地操作表格。 具体来说,该组件的使用方法非常简单,只需在Vue的template中引入element-plus-table-dragable并设置相关的props即可。例如,下面的代码片段演示如何生成一个具有两行三列的表格并启用拖拽排序和列宽度调整功能: <element-plus-table-dragable :data="tableData" :dragSort="true" :resize="true"> <el-table-column label="姓名" prop="name"></el-table-column> <el-table-column label="年龄" prop="age"></el-table-column> <el-table-column label="地址" prop="address"></el-table-column> </element-plus-table-dragable> 上述代码中,tableData是表格要显示的数据,dragSort和resize分别用于启用拖拽排序和列宽度调整功能。此外,用户还可以根据自己的需求来选择是否用slot来自定义表格的内容。 总之,element-plus-table-dragable组件为Vue.jsElement Plus用户提供了更多实用的表格操作功能,通过拖拽排序和列宽度调整,用户可以更高效地管理和处理表格数据,从而提高工作效率和可靠性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值