vue项目中table表格固定表头和首尾列

本文详细介绍了在Vue项目中,结合Element UI和Quasar框架,以及自定义的table组件,如何实现table表格的固定表头和首尾列。针对vue+element,只需设置`height`或`max-height`属性并使用`fixed`属性即可;在vue+quasar中,借助q-table组件和CSS实现;对于自封装的table组件,通过监听滚动事件和CSS变换来达到固定效果。
摘要由CSDN通过智能技术生成

在html中实现table表格固定表头和首尾列的方法和文章很多,本文就不再赘述。
本文主要介绍vue项目中三种情景下实现table表格固定表头和首尾列
情景一:vue+element
只要在el-table元素中定义了height属性,即可实现固定表头的表格
通过设置max-height属性为 Table 指定最大高度。此时若表格所需的高度大于最大高度,则会显示一个滚动条。
固定列需要使用fixed属性,它接受 Boolean 值或者leftright,表示左边固定还是右边固定。

<template>
  <el-table :data="tableData" style="width: 100%" max-height="250">
      <el-table-column fixed prop="date" label="日期" width="150">
      </el-table-column>
      <el-table-column prop="name" label="姓名" width="120">
      </el-table-column>
      <el-table-column prop="province" label="省份" width="120">
      </el-table-column>
      <el-table-column prop="city" label="市区" width="120">
      </el-table-column>
      <el-table-column prop="address" label="地址" width="300">
      </el-table-column>
      <el-table-column prop="zip" label="邮编" width="120">
      </el-table-column>
      <el-table-column
        fixed="right" label="操作" width="120">
        <template slot-scope="scope">
          <el-button
            @click.native.prevent="deleteRow(scope.$index, tableData)"
            type="text"
            size="small">
            移除
          </el-button>
        </template>
      </el-table-column>
    </el-table>
</template>
<script>
  export default {
    methods: {
      deleteRow(index, rows) {
        rows.splice(index, 1);
      }
    },
    data() {
      return {
        tableData: [{
          date: '2016-05-03',
          name: '王小虎',
          province: '上海',
          city: '普陀区',
          address: '上海市普陀区金沙江路 1518 弄',
          zip: 200333
        }, ......, {
          date: '2016-05-07',
          name: '王小虎',
          province: '上海',
          city: '普陀区',
          address: '上海市普陀区金沙江路 1518 弄',
          zip: 200333
        }]
      }
    }
  }
</script>

情景二:vue+quasar

<template>
  <div class="q-pa-md">
    <q-table
      class="my-sticky-header-column-table"
      title="Treats"
      :data="data"
      :columns="columns"
      row-key="name"
    />
  </div>
</template>
<script>
export default {
  data () {
    return {
      columns: [
        {name: 'name', required: true, label: 'Dessert (100g serving)',  align: 'left', field: row => row.name, format: val => `${val}`,  sortable: tru},
       { name: 'calories', align: 'center', label: 'Calories', field: 'calories', sortable: true},
 	   { name: 'fat', label: 'Fat (g)', field: 'fat', sortable: true },
       { name: 'carbs', label: 'Carbs (g)', field: 'carbs', sortable: true },
       { name: 'protein', label: 'Protein (g)', field: 'protein', sortable: true},
       { name: 'sodium', label: 'Sodium (mg)', field: 'sodium', sortable: true},
       { name: 'calcium', label: 'Calcium (%)', field: 'calcium', sortable: true, sort: (a, b) => parseInt(a, 10) - parseInt(b, 10)},
       { name: 'iron', label: 'Iron (%)', field: 'iron', sortable: true, sort: (a, b) => parseInt(a, 10) - parseInt(b, 10)}],
data: [{ name: 'Frozen Yogurt', calories: 159, fat: 6.0, carbs: 24, protein: 4.0, sodium: 87, calcium: '14%', iron: '1%'},
       { name: 'Ice cream sandwich', calories: 237, fat: 9.0, carbs: 37, protein: 4.3, sodium: 129, calcium: '8%', iron: '1%'},
       { name: 'Eclair', calories: 262, fat: 16.0, carbs: 23, protein: 6.0, sodium: 337, calcium: '6%', iron: '7%'},
       { name: 'Cupcake', calories: 305, fat: 3.7, carbs: 67, protein: 4.3, sodium: 413, calcium: '3%', iron: '8%'},
       { name: 'Gingerbread', calories: 356, fat: 16.0, carbs: 49, protein: 3.9, sodium: 327, calcium: '7%', iron: '16%'},
       { name: 'Jelly bean', calories: 375, fat: 0.0, carbs: 94, protein: 0.0, sodium: 50, calcium: '0%', iron: '0%'},
       { name: 'Lollipop', calories: 392, fat: 0.2, carbs: 98, protein: 0, sodium: 38, calcium: '0%', iron: '2%'},
       { name: 'Honeycomb', calories: 408, fat: 3.2, carbs: 87, protein: 6.5, sodium: 562, calcium: '0%', iron: '45%'},
       { name: 'Donut', calories: 452, fat: 25.0, carbs: 51, protein: 4.9, sodium: 326, calcium: '2%', iron: '22%'},
       { name: 'KitKat', calories: 518, fat: 26.0, carbs: 65, protein: 7, sodium: 54, calcium: '12%', iron: '6%'}]
    }
  }
}
</script>
<style lang="sass">
.my-sticky-header-column-table{
  /* height or max-height is important */
  height: 310px
  /* specifying max-width so the example can
    highlight the sticky column on any browser window */
  max-width: 600px
  td:first-child{
    /* bg color is important for td; just specify one */
    background-color: #c1f4cd !important
}
  tr th{
    position: sticky
    /* higher than z-index for td below */
    z-index: 2
    /* bg color is important; just specify one */
    background: #fff
}
  /* this will be the loading indicator */
  thead tr:last-child th{
    /* height of all previous header rows */
    top: 48px
    /* highest z-index */
    z-index: 3
}
  thead tr:first-child th{
    top: 0
    z-index: 1
}
  tr:first-child th:first-child{
    /* highest z-index */
    z-index: 3
}
  td:first-child{
    z-index: 1
}
  td:first-child, th:first-child{
    position: sticky
    left: 0
}
}
</style>

情景三:vue+自己封装的table组件或js的table标签

<template>
<!--overflow:auto为超出tableDiv的宽高才显示滚动条,宽高可以是通过动态计算得到的 -->
  <div id="tableDiv" style="width:500px; height:400px;overflow:auto;margin:0 auto;margin-top:50px;">
	  <!-- table必须加transform这个样式,否则垂直滚动的时候,会有问题 -->
	  <table style="transform-style:preserve-3d;">
	    <thead>
	    <tr>
	      <th style="width:50px">Num</th>
	      <th style="width:120px">Name</th>
	      <th style="width:100px">Age</th>
	      <th style="width:300px">Address</th>
	      <th style="width:50px">Opt</th>
	    </tr>
	    </thead>
	    <tbody>
	    <tr>
	      <td>1</td>
	      <td>张三</td>
	      <td>10</td>
	      <td>这是一条很长很长很长很长很长很长很长很长的文字</td>
	      <td>
	        <a href="">编辑</a>
	      </td>
	    </tr>
	    .......
	    <tr>
	      <td>12</td>
	      <td>张三12</td>
	      <td>10</td>
	      <td>这是一条很长很长很长很长很长很长很长很长的文字</td>
	      <td>
	        <a href="">编辑</a>
	      </td>
	    </tr>
	    </tbody>
	  </table>
	</div>
</template>
<script>
export default {
 data () {
    return {}
    }
  methods: {
 // 因为要操作dom元素,在mounted中调用没问题,但是为避免在其他地方调用时dom还未加载,加个$nextTick()
	  this.$nextTick(() => {
		  fixtable () {
		        //这是外层div
		        var tableDiv = document.querySelector("#tableDiv");
		        //这是水平可滚动距离
		        var diff = tableDiv.scrollWidth - tableDiv.clientWidth;
		        //获取最后一列单元格,在这个例子里,最后一列是第5列
		        var lasts = tableDiv.querySelectorAll("tr td:nth-last-child(1),tr th:nth-last-child(1)");
		        //获取第一列列单元格
		        var firsts = tableDiv.querySelectorAll("tr td:nth-child(1),tr th:nth-child(1)");
		        //如果水平有滚动条,那一开始就需要让最后一列偏移
		        if (diff > 0) {
		          for (var i = 0; i < lasts.length; i++) {
		            lasts[i].style.transform = "translateX(-" + diff + "px)";
		          }
		        }
		        /*******固定的逻辑基本就下面这些*********/
		        var scroll_x = 0;
		        var scroll_y = 0;
		        tableDiv.addEventListener("scroll", function (e) {
		          //垂直滚动固定头
		          if (this.scrollTop != scroll_y) {
		            scroll_y = this.scrollTop;
		            this.querySelector("thead").style.transform = "translate3d(0," + this.scrollTop + "px,.1px)";
		          }
		          //水平滚动固定前两列和最后一列
		          if (this.scrollLeft != scroll_x) {
		            scroll_x = this.scrollLeft;
		            for (var i = 0; i < lasts.length; i++) {
		              lasts[i].style.transform = "translateX(-" + (diff - scroll_x) + "px)";
		            }
		            for (var i = 0; i < firsts.length; i++) {
		              firsts [i].style.transform = "translateX(" + scroll_x + "px)";
		            }
		          }
		        })
		      }
		  })
	      mounted() {
	      	this.fixtable ()
	      }
	    }
  	}
 </script>
 <style>
      table {
        /*给table标签添加border-collapse: collapse属性,用于合并表格边框*/
        border-collapse: collapse;
        /*使用fixed实现th固定宽度,一般情况我们会让列宽自适应,可不设table-layout*/
        table-layout: fixed;
         /*在使用fixed的时候,必须指定width,否则还是自适应宽度*/
        width: 100%;
        border-spacing: 0;
      }
      th {
        background: #888;
         /*设个outline不然滚动会看着不协调*/
        outline: 1px solid #333;
      }
      table th:nth-last-child(1){
      background: #fff;
      outline: 1px solid #333;
      }
      table th:nth-child(1){
      background: #fff;
      outline: 1px solid #333;
      }
      th,
      td {
        border: 1px solid #333;
        background: #fff;
      }
    </style>
Vue原生的table表格表头固定,可以通过CSS的position属性和JS的scroll事件来实现。 首先,在table标签外面嵌套一个div容器,设置其样式为position: relative,用于容纳表格表头。 然后,在表格表头的tr标签上添加一个ref属性,用于在JS获取该元素。 接下来,使用JS监听div容器的scroll事件,在事件通过ref获取到表头元素,并获取该元素的offsetTop和scrollTop属性值。 然后,判断scrollTop是否大于或等于offsetTop,如果是则添加一个css类或样式,将表头固定在顶部;如果不是,则移除该类或样式。 最后,将改变样式的操作放在一个debounce的函数,用于优化滚动事件的性能。 具体代码如下: <template> <div class="container" ref="container" @scroll="handleScroll"> <table class="table"> <thead> <tr ref="thead"> <th>表头1</th> <th>表头2</th> <th>表头3</th> </tr> </thead> <tbody> <tr> <td>内容1</td> <td>内容2</td> <td>内容3</td> </tr> ... </tbody> </table> </div> </template> <script> export default { methods: { handleScroll() { const container = this.$refs.container; const thead = this.$refs.thead; const offsetTop = thead.offsetTop; const scrollTop = container.scrollTop; if (scrollTop >= offsetTop) { thead.classList.add("fixed"); } else { thead.classList.remove("fixed"); } }, }, }; </script> <style> .container { position: relative; max-height: 300px; overflow-y: scroll; } .fixed { position: fixed; top: 0; left: 0; width: 100%; z-index: 999; } .table { width: 100%; } /* 省略其他样式 */ </style> 以上就是利用Vue原生实现table表格表头固定的方法。通过设置CSS样式和监听scroll事件,可以在滚动时使表头保持在页面顶部。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值