一次表格及分页优化完善实践,表头固定及分页固定(模仿禅道)

40 篇文章 6 订阅
需求:

1、当表格数据未查看到最后一条时,分页固定在页面最下方,直到查看表格最后一行,分页取消固定;
2、当表格滑动到上方,表头固定在系统的上方

思路:

1、当鼠标滑动时判断表格距离浏览器上方的距离,当距离小于系统头部时,表头固定,反之取消固定, 可以使用@wheel获取滑轮滚动事件,也可以使用window.addEventListener监听滑动条滑动事件scroll
2、表头固定的方式有三种:

  • 方法一:给el-table的height赋值,获取表格中滚动条滚动到最后一行,始终差着点值,不知道什么原因,考虑不周,想加占位符试试,最初实现了,但是因为高度固定,后面的占位符一直可视,所以冲突了,所以使用了方法二
  • 方法二:使用一模一样的表格,把原表格的表头隐藏,把新表格的内容隐藏
  • 方法三:自己使用div照着表头的样式写一个,个人不太喜欢这种

3、新增一个占位符在表格的下方,当该元素不在可视区域时,分页固定,反之,取消固定

反思:

1、@wheel获取滑轮滚动事件先触发,获取不到滚动条滑动的正确距离,所以有延迟
2、 固定表格时,由于考虑不周,忘记了固定了表格高度,元素就一直可见了,想用方法一和方法二结合做
3、改着改着代码手滑把判断表格距离浏览器上方的距离 <= 系统头部,写成了>头部
4、在销毁前移除监听器的时候没有加true参数,导致报错Cannot read property ‘getBoundingClientRect‘ of undefined

自己修改封装的分页组件Pagination.vue
<template>
    <div :class= "{ 'fixed-foot': isFixed, 'pagination': !isFixed }">
      <el-pagination
          v-if="isSmall"
          small
          @size-change="handleSizeChange"
          @current-change="handleCurrentChange"
          layout="total, prev, pager, next"
          :page-size="page.pageSize"
          :total="page.total">
      </el-pagination>

      <el-pagination
          :page-sizes="[10, 50, 100,500]"
          layout="total,sizes,prev, pager, next,jumper"
          :total="page.total"
          :page-size="page.pageSize"
          :current-page="page.currentPage"
          @current-change="handleCurrentChange"
          @size-change="handleSizeChange">
      </el-pagination>

    </div>
</template>
<script>
export default {
  name: 'pagination', //分页组件
  props: {
    page: {
      type: Object,
      default: {}
    },
    enableSmall: {
      type: Boolean,
      default: false,
    },
    isFixed: {
      type: Boolean,
      default: true,
    }
  },
  data() {
    return {
      isSmall: this.enableSmall || false, //是否启用small模式
    }
  },
  methods: {
    handleCurrentChange(val){
      this.$emit('pageChange', val);
    },
    handleSizeChange(val) {
      console.log(`每页 ${val} 条`);
      this.$emit('pageChangeSize', val);
    }
  }
}
</script>
<style lang="less" scoped>
.pagination{
  position: absolute;
  bottom: 52px;
  width: calc(100% - 216px);
  margin: 0 !important;
  text-align: right;

  .el-pagination{
    padding: 10px 10px 10px 0 !important;
    background-color: rgba(99, 99, 99, 0.6);
  }
}

.fixed-foot{
  position: fixed;
  width: calc(100% - 216px);
  right: 10px;
  bottom: 0;
  margin: 0 !important;
  text-align: right;

  .el-pagination{
    padding: 10px 10px 10px 0 !important;
    background-color: rgba(99, 99, 99, 0.6);
  }
}

/deep/.el-pagination__total{
  color: #fff;
}

/deep/ .el-input__inner,
/deep/ .btn-prev,
/deep/ .btn-next,
/deep/ .el-pager li{
  border: 1px solid transparent;
  background-color: rgba(99, 99, 99, 0.6);
  color: #fff;
}

/deep/ .el-pager li.active{
  color: #409EFF;
}

/deep/ .el-pagination button:disabled{
  background-color: rgba(99, 99, 99, 0.6);
}

/deep/ .el-pagination__jump{
  color: #fff;
}
</style>

主要实现代码test.vue
<template>
  <div class="mainbox">
    <el-table :data="emptyData" class="table-head" v-if="isFixedHead">
      <el-table-column prop="NO" type="index" label="序号" width="70" align="center"></el-table-column>
      <el-table-column prop="a" label="1"></el-table-column>
      <el-table-column prop="b" label="2"></el-table-column>
      <el-table-column prop="c" label="3"></el-table-column>
      <el-table-column prop="d" label="4"></el-table-column>
      <el-table-column prop="e" label="5"></el-table-column>
      <el-table-column prop="f" label="6"></el-table-column>
    </el-table>
    <el-table id="alarmTable" :data="tableData" border stripe class="timeline-table">
      <el-table-column prop="NO" type="index" label="序号" width="70" align="center"></el-table-column>
      <el-table-column prop="a" label="1"></el-table-column>
      <el-table-column prop="b" label="2"></el-table-column>
      <el-table-column prop="c" label="3"></el-table-column>
      <el-table-column prop="d" label="4"></el-table-column>
      <el-table-column prop="e" label="5"></el-table-column>
      <el-table-column prop="f" label="6"></el-table-column>
    </el-table>
    <Pagination ref="pagination" :page="page" :isFixed="isFixedFoot" @pageChange="pageChange" @pageChangeSize="pageChangeSize" v-if="page.total > 10"></Pagination>
    <div class="placeholder" id="placeholder"></div>
  </div>
</template>

<script>

export default {
  name: "test",
  components: {
    Pagination: () => import('@components/common/Pagination')
  },
  data() {
    return {
      page:{
        currentPage: 1,
        pageSize: this.global.pageSize,
        total: 0,
      },
      tableData: [],
      isFixedFoot: true,
      isFixedHead: null,
      emptyData: []
    }
  },
  mounted() {
    window.addEventListener('scroll', this.handleScroll, true)
  },
 // 页面销毁前
 beforeDestroy() {
   window.removeEventListener('scroll', this.handleScroll, true)
 },
  methods: {
    placeholderVisible(){
      let rect = document.getElementById('placeholder').getBoundingClientRect()
      const viewHeight = window.innerHeight || document.documentElement.clientHeight
      console.log('判断', rect.bottom, window.innerHeight)
      if(rect.bottom <= viewHeight){
        console.log('元素出现')
        this.isFixedFoot = false
      }else{
        console.log('元素消失')
        this.isFixedFoot = true
      }
    },
    handleScroll() {
      let offsetTop = document.getElementById('table').getBoundingClientRect().top
      if(offsetTop < 100){
        console.log('固定')
        this.isFixedHead = true
      }else{
        console.log('移除固定')
        this.isFixedHead = false
      }
      this.placeholderVisible()
    },
    loadTable(){
      // 获取数据加载表格
    },
    pageChange(val){
      //分页
      this.page.currentPage = val
      this.loadTable()
    },
    pageChangeSize(val){
      //分页
      this.page.pageSize = val
      this.global.pageSize = val
      this.loadTable()
    }
  },

}
</script>

<style lang="less" scoped>
.mainbox{
  width: calc(100% - 10px);

  .table-head{
    position: fixed;
    top: 100px;
    z-index: 1;
    width: calc(100% - 216px);

    /deep/ .el-table__header {
      background-color: rgba(26, 64, 139, 0.9);
    }

    /deep/ .el-table__row,
    /deep/ .el-table__empty-block{
      display: none;
    }
  }

  .placeholder{
    min-height: 100px;
  }
}
</style>

效果图如下,文字部分已打码
在这里插入图片描述

部分作废代码也记录一下吧,没准以后用的到

// 获取表格对象
      let dom = document.querySelector('.el-table__body-wrapper')
      dom.addEventListener("scroll", () => {
        const scrollDistance = dom.scrollHeight - dom.scrollTop - dom.clientHeight;
        // 判断是否到底
        if (scrollDistance <= 1) {
          console.log('已经见底了')
          this.fixedFoot = false
          this.isFixed = false
        }else{
          this.isFixed = true
        }
      })
      let scrollTop = this.$refs.table.bodyWrapper.scrollTop
      let scrollHeight = this.$refs.table.bodyWrapper.scrollHeight
      console.log('差值', scrollHeight, scrollTop, scrollHeight - scrollTop)
      this.$refs.table.bodyWrapper.scrollTop =this.$refs.table.bodyWrapper.scrollHeight;
      let scrollHeight = this.$refs.table.bodyWrapper.scrollHeight
      this.$refs.table.bodyWrapper.scrollTop = scrollHeight
      if(scrollHeight - scrollTop <= 605){
        // alert('滑动到底部')
      }
      let placeholder = document.getElementById('placeholder')
      if(document.documentElement.contains(placeholder)){
        console.log('滑动到底部')
      }

主要参考文章:
JS判断元素是否在可视区域
vue 中 elementUI el-table 实现滚动加载
关于scroll事件与wheel事件的区别
Cannot read property ‘getBoundingClientRect‘ of undefined

如果大家想一起交流学习,共同进步,欢迎搜索公众号“是日前端”,输入关键词如:前端基础,获取资料,资料刚开始整理,目前还在完善中,点击交流群按钮进交流群,群里仅限技术交流、面试交流等,需要其它相关资料可以群里说,后续交流群人数增多会考虑特色内容,再次感谢大家的支持~

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值