好久都沒有寫文章了,上個月業務繁忙,事情比較多,最近在做移動端中發現了一個好玩的事情,那就是移動端中實現表格,固定列有哪些方法:
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端的效果如下:
pc端的效果咋們都可以接收,雖然會有點看起來不舒服。
移動端效果
這啥呀,還抖動的,對於真機的測試,安卓會抖動,但是蘋果機型不會抖動。這種肯定是不行的,打開ele的table看到人家的表格蠻不錯的,那就學習下。
2.多表格實現固定
思路,在ele中,固定是有多個表格來的,所以咋也來搞多個表格。首先將表格分成左右兩部分,左邊第一列在上下滑動是header部分需要固定;右邊第一行在左右滑動時firstRow和header部分也需要是固定的。可將這幾個划分區域分別用table填充,滑動tableBody時保持firstRow和firstCol的同步滑動即可。
看看效果圖
這回總不會抖動了吧,為了方便大家學習,我就把我的這個組件貢獻出來。讓有需要的同學使用,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>
轉載請注明來源:點擊領取 http://www.dianjilingqu.com/