vue2,vue3移动端实现表格固定和首列固定

简介: 粘性布局,这个属性也可以实现行和列的固定,在pc端上没有啥问题,但是在手机端上会抖动。

好久都没有写文章了,上个月业务繁忙,事情比较多,最近在做移动端中发现了一个好玩的事情,那就是移动端中实现表格,固定列有哪些方法:


1. position: sticky


粘性布局,这个属性也可以实现行和列的固定,在pc端上没有啥问题,但是在手机端上会抖动。


使用注意事项:


要求父级不能够使用overflow:auto,否则不生效。


牛刀小试


<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Test</title>
  <style>
    *,
    body,
    html {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
      height: 100%;
      width: 100%;
    }
    .condition {
      height: 50px;
      background-color: rgb(19, 13, 13);
      color: #fff;
      font-size: 2em;
      text-align: center;
    }
    .table-container {
      width: 100%;
      height: calc(100% - 50px);
      overflow: auto;
    }
    table {
      border-collapse: collapse;
    }
    th,
    td {
      padding: 5px;
      text-align: center;
      border: 1px solid #999;
      min-width: 100px;
    }
    th {
      background-color: #333;
      color: #fff;
      position: sticky;
      top: 0px;
    }
    td:first-child {
      background-color: #333;
      color: #fff;
      position: sticky;
      left: 0px;
    }
    th:first-child {
      position: sticky;
      left: 0px;
      top: 0px;
      z-index: 10;
    }
  </style>
  <script src="https://cdn.staticfile.org/vue/2.5.17-beta.0/vue.min.js"></script>
  <script>
    document.addEventListener("DOMContentLoaded", function () {
      let t = new Vue({ el: "#app" });
    });
  </script>
</head>
<body>
  <div id="app">
    <!-- 其他东西 -->
    <div class="condition">条件查询</div>
    <div class="table-container">
      <table>
        <thead>
          <tr>
            <th v-for="(n,i) of 50">字段 {{i+1}}</th>
          </tr>
        </thead>
        <tbody>
          <tr v-for="(n,i) of 100">
            <td v-for="(m,j) of 50">{{j+1}}</td>
          </tr>
        </tbody>
      </table>
    </div>
  </div>
</body>
</html>


pc端的效果如下:


fa501201a3fd44e6ba312252638eafb2.gif


pc端的效果咋们都可以接收,虽然会有点看起来不舒服。


移动端效果


154fa48ff5894436b5cc92360047bb7c.gif


这啥呀,还抖动的,对于真机的测试,安卓会抖动,但是苹果机型不会抖动。这种肯定是不行的,打开ele的table看到人家的表格蛮不错的,那就学习下。


2.多表格实现固定


思路,在ele中,固定是有多个表格来的,所以咋也来搞多个表格。首先将表格分成左右两部分,左边第一列在上下滑动是header部分需要固定;右边第一行在左右滑动时firstRow和header部分也需要是固定的。可将这几个划分区域分别用table填充,滑动tableBody时保持firstRow和firstCol的同步滑动即可。


02dbf2aade014b6ab3e766acc3b93e81.png


看看效果图


e4cab87ac96a4c3eace45d392d3a8dba.gif


这回总不会抖动了吧,为了方便大家学习,我就把我的这个组件贡献出来。让有需要的同学使用,vue3都出来了这么久,肯定用vue3了哇!


<script lang='ts' setup>
import { computed, Ref, ref } from 'vue'
const props = defineProps<{
  // 传我表头,表头的列数,需要和tableData每一个对象里的属性值一样
  headerData: { title: string, props: string }[],
  // 表格数据
  tableData: { [key: string]: any }[],
  // 表格高度
  tableScrollHeight: number
}>()
const tableContainer: Ref<HTMLDivElement | null> = ref(null);
const firstRowLayer: Ref<HTMLDivElement | null> = ref(null);
const firstColLayer: Ref<HTMLDivElement | null> = ref(null);
// 第一列数据
const firstCol = computed(() => props.tableData.map(p => {
  const pArr = Object.keys(p);
  return p[pArr[0]]
}))
// 第一个表头,第一列
const header = computed(() => props.headerData[0].title);
// 第一行
const firstRow = computed(() => {
  const rows: string[] = [];
  props.headerData.forEach((f, i) => {
    if (i !== 0) {
      rows.push(f.title)
    }
  })
  return rows;
})
// 表格内容行
const tableBodyRows = computed(() => {
  let arr: { [key: string]: any }[] = [];
  props.tableData.forEach((f, index) => {
    // 接下来排除第一列
    let res: { [key: string]: any } = {};
    for (const key in f) {
      if (Object.prototype.hasOwnProperty.call(f, key)) {
        if (key !== props.headerData[0].title) {
          res[key] = f[key]
        }
      }
    }
    arr.push(res)
  })
  return arr
})
// 表格内容列
const tableBodyCols = computed(() => {
  let arr: { title: string, props: string }[] = []
  props.headerData.forEach((f, i) => {
    if (i !== 0) {
      arr.push(f)
    }
  })
  return arr;
})
// table滚动
const tableScroll = () => {
  // 首行固定
  firstRowLayer.value!.scrollLeft = tableContainer.value!.scrollLeft;
  // 首列固定
  firstColLayer.value!.scrollTop = tableContainer.value!.scrollTop;
}
</script>
<template>
  <div class="content-table">
    <template v-if="props.tableData.length > 0">
      <div class="left-div">
        <div class="left-div1">
          <table>
            <tr>
              <th>{{ header }}</th>
            </tr>
          </table>
        </div>
        <div
          ref="firstColLayer"
          class="left-div2"
          :style="{ height: `calc(100vh - ${tableScrollHeight}px` }"
        >
          <table class="left-table2">
            <tr v-for="(col, index) in firstCol" :key="index">
              <td>{{ col }}</td>
            </tr>
          </table>
        </div>
      </div>
      <div class="right-div">
        <div ref="firstRowLayer" class="right-div1">
          <table class="right-table1" :style="{ width: (firstRow.length - 1) * 100 + 'px' }">
            <tr>
              <th class="first-row-style" v-for="(row, index) in firstRow" :key="index">{{ row }}</th>
            </tr>
          </table>
        </div>
        <div
          ref="tableContainer"
          class="right-div2"
          :style="{ height: `calc(100vh - ${tableScrollHeight}px` }"
          @scroll="tableScroll()"
        >
          <table class="right-table2" :style="{ width: (firstRow.length - 1) * 100 + 'px' }">
            <tr v-for="(body,index) in tableBodyRows" :key="index">
              <td v-for="(col, i) in tableBodyCols" :key="col.props + i">{{ body[col.props] }}</td>
            </tr>
          </table>
        </div>
      </div>
    </template>
    <template v-else>
      <div class="empty-content">
        <table
          cellspacing="0"
          :style="{ width: (headerData.length - 1) * 100 + 'px', height: '10rem', overflow: 'auto' }"
        >
          <thead class="table-header">
            <tr>
              <th v-for="(item,index) in props.headerData" :key="item.title">{{ item.title }}</th>
            </tr>
          </thead>
          <van-empty class="empty-res" description="空空如也!" />
        </table>
      </div>
    </template>
  </div>
</template>
<style lang="scss" scoped>
.content-table {
  box-sizing: border-box;
  overflow-x: hidden;
}
table {
  border-collapse: collapse;
  margin: 0 auto;
  width: 100%;
  border-spacing: 0;
  font-size: 13px;
}
th {
  word-break: break-all;
  word-wrap: break-word;
  height: 40px;
  width: 100px;
  vertical-align: middle;
  text-align: center;
  border-left: 1px solid #999;
  background: #d9d9d9;
  box-sizing: border-box;
}
td {
  word-break: break-all;
  word-wrap: break-word;
  width: 100px;
  text-align: center;
  vertical-align: middle;
  line-height: 30px;
  border-left: 1px solid #999;
  box-sizing: border-box;
}
tr {
  border-top: 1px solid #999;
  box-sizing: border-box;
}
.left-div {
  width: 100px;
  float: left;
}
.left-div1 {
  width: 100%;
}
.left-div2 {
  width: 100%;
  overflow: hidden;
}
.left-table2 {
  margin-bottom: 4px;
}
.right-div {
  float: left;
  width: calc(100vw - 100px);
  margin-left: -1px;
}
.right-div1 {
  width: 100%;
  overflow: hidden;
  .first-row-style {
    box-sizing: border-box;
  }
}
.right-div2 {
  width: 100%;
  overflow: auto;
}
.right-table2 {
  overflow: hidden;
}
table tr:nth-child(odd) {
  background: rgba(255, 255, 255, 0.3);
}
table tr:nth-child(even) {
  background: rgba(153, 153, 153, 0.3);
}
.empty-content {
  width: 100%;
  overflow: auto;
}
</style>


上个月自己也用vue3写了个前台的管理系统,有需要的可以看看哦!http://ruoyi-doc.chenliangliang.top/

相关文章
|
13天前
|
缓存 JavaScript UED
Vue3中v-model在处理自定义组件双向数据绑定时有哪些注意事项?
在使用`v-model`处理自定义组件双向数据绑定时,要仔细考虑各种因素,确保数据的准确传递和更新,同时提供良好的用户体验和代码可维护性。通过合理的设计和注意事项的遵循,能够更好地发挥`v-model`的优势,实现高效的双向数据绑定效果。
116 64
|
13天前
|
JavaScript 前端开发 API
Vue 3 中 v-model 与 Vue 2 中 v-model 的区别是什么?
总的来说,Vue 3 中的 `v-model` 在灵活性、与组合式 API 的结合、对自定义组件的支持等方面都有了明显的提升和改进,使其更适应现代前端开发的需求和趋势。但需要注意的是,在迁移过程中可能需要对一些代码进行调整和适配。
|
1月前
|
JavaScript 前端开发 开发者
Vue 3中的Proxy
【10月更文挑战第23天】Vue 3中的`Proxy`为响应式系统带来了更强大、更灵活的功能,解决了Vue 2中响应式系统的一些局限性,同时在性能方面也有一定的提升,为开发者提供了更好的开发体验和性能保障。
63 7
|
1月前
|
JavaScript 数据管理 Java
在 Vue 3 中使用 Proxy 实现数据双向绑定的性能如何?
【10月更文挑战第23天】Vue 3中使用Proxy实现数据双向绑定在多个方面都带来了性能的提升,从更高效的响应式追踪、更好的初始化性能、对数组操作的优化到更优的内存管理等,使得Vue 3在处理复杂的应用场景和大量数据时能够更加高效和稳定地运行。
52 1
|
1月前
|
JavaScript 开发者
在 Vue 3 中使用 Proxy 实现数据的双向绑定
【10月更文挑战第23天】Vue 3利用 `Proxy` 实现了数据的双向绑定,无论是使用内置的指令如 `v-model`,还是通过自定义事件或自定义指令,都能够方便地实现数据与视图之间的双向交互,满足不同场景下的开发需求。
56 1
|
19天前
|
缓存 JavaScript 前端开发
vue学习第四章
欢迎来到我的博客!我是瑞雨溪,一名热爱JavaScript与Vue的大一学生。本文介绍了Vue中计算属性的基本与复杂使用、setter/getter、与methods的对比及与侦听器的总结。如果你觉得有用,请关注我,将持续更新更多优质内容!🎉🎉🎉
34 1
vue学习第四章
|
19天前
|
JavaScript 前端开发
vue学习第九章(v-model)
欢迎来到我的博客,我是瑞雨溪,一名热爱JavaScript与Vue的大一学生,自学前端2年半,正向全栈进发。此篇介绍v-model在不同表单元素中的应用及修饰符的使用,希望能对你有所帮助。关注我,持续更新中!🎉🎉🎉
28 1
vue学习第九章(v-model)
|
19天前
|
JavaScript 前端开发 开发者
vue学习第十章(组件开发)
欢迎来到瑞雨溪的博客,一名热爱JavaScript与Vue的大一学生。本文深入讲解Vue组件的基本使用、全局与局部组件、父子组件通信及数据传递等内容,适合前端开发者学习参考。持续更新中,期待您的关注!🎉🎉🎉
33 1
vue学习第十章(组件开发)
|
25天前
|
JavaScript 前端开发
如何在 Vue 项目中配置 Tree Shaking?
通过以上针对 Webpack 或 Rollup 的配置方法,就可以在 Vue 项目中有效地启用 Tree Shaking,从而优化项目的打包体积,提高项目的性能和加载速度。在实际配置过程中,需要根据项目的具体情况和需求,对配置进行适当的调整和优化。
|
25天前
|
存储 缓存 JavaScript
在 Vue 中使用 computed 和 watch 时,性能问题探讨
本文探讨了在 Vue.js 中使用 computed 计算属性和 watch 监听器时可能遇到的性能问题,并提供了优化建议,帮助开发者提高应用性能。