原理是将原table的指定行,指定列clone一份放在其上
实现代码如下:
<template> <div> <div id="divBox1" :style="{height:height}"> <table id="tbTest1" cellpadding="0" cellspacing="0" style="text-align:center;background:rgba(244,249,255,0.4);"> <tr> <th v-for="item in thead" @click="sortBy(item)"> {{item}}<img style="width:0.16rem;height:0.20rem;margin-left:4px;" :src="filterUrl" alt="" v-if="$index!=0" data-img="{{filterUrl}}"> </th> </tr> <tr v-for="row in tableRows | orderBy sortBykey sortOrders[sortKey]"> <td style="overflow:hidden;white-space:nowrap;" v-for="item in gridColumns" v-html="row[item] | numberFilter" :id="$parent.$index"> </td> </tr> </table> </div> </div> </template> <script> /*eslint-disable*/ var ofixed_table_st = window.setTimeout; var hasLeft = ''; var hasHead = ''; window.setTimeout = function(fRef, mDelay) { if(typeof fRef == 'function') { var argu = Array.prototype.slice.call(arguments, 2); var f = (function() { fRef.apply(null, argu); }); return ofixed_table_st(f, mDelay); } return ofixed_table_st(fRef, mDelay); }; function oFixedTable(id, obj, _cfg) { this.id = id; this.obj = obj; this.box = this.obj.parentNode; this.config = { fixHead: _cfg.fixHead || true, rows: _cfg.rows || 1, cols: _cfg.cols || 0, background: _cfg.background || '#ffffff', zindex: _cfg.zindex || 10 }; window.setTimeout(this._fixTable, 100, this); } oFixedTable.prototype._fixTable = function(_) { if(_.obj.rows.length <= 0) { return false; } var hasLeft = _.buildLeft(); var hasHead = _.buildHead(); _.box.onscroll = function() { if(_.divHead != null) { _.divHead.scrollLeft = this.scrollLeft; } if(_.divLeft != null) { _.divLeft.scrollTop = this.scrollTop; } }; if(hasHead && hasLeft) { _.buildTopLeft(); } }; oFixedTable.prototype.buildHead = function() { console.log(2222222222222222222) var _ = this; var strDivId = _.id + '_div_head'; var strTbId = _.id + '_tb_header'; var div = document.createElement('div'); div.id = strDivId; div.style.cssText = 'position:absolute;overflow:hidden;z-index:' + (_.config.zindex + 1) + ';'; div.innerHTML = '<table id="' + strTbId + '" cellpadding="0" cellspacing="0" style="background:' + _.config.background + ';"></table>'; _.box.insertBefore(div, _.obj); _.divHead = div; _.tbHead = document.getElementById(strTbId); //判断是否出现纵向滚动条,若出现,高度减去滚动条宽度 16px var sw = _.obj.offsetHeight > _.box.offsetHeight ? 0 : 0; _.divHead.style.width = (_.box.offsetWidth - sw) + 'px'; _.tbHead.style.textAlign = _.obj.style.textAlign; _.tbHead.style.width = _.obj.offsetWidth + 'px'; var hasHead = false; if(_.config.fixHead && _.obj.tHead != null) { var tHead = _.obj.tHead; _.tbHead.appendChild(tHead.cloneNode(true)); hasHead = true; } else { for(var i = 0; i < _.config.rows; i++) { var row = _.obj.rows[i]; if(row != null) { _.tbHead.appendChild(row.cloneNode(true)); hasHead = true; } } } return hasHead; }; oFixedTable.prototype.buildLeft = function() { var _ = this; if(_.config.cols <= 0) { return false; } var strDivId = _.id + '_div_left'; var strTbId = _.id + '_tb_left'; var div = document.createElement('div'); div.id = strDivId; div.style.cssText = 'position:absolute;overflow:hidden;z-index:' + _.config.zindex + ';box-shadow: #dddddd 2px 0px 2px;width: 2rem;'; div.innerHTML = '<table id=' + strTbId + ' cellpadding="0" cellspacing="0" style="background:' + _.config.background + ';width: 2rem;"></table>'; _.box.insertBefore(div, _.obj); _.divLeft = div; _.tbLeft = document.getElementById(strTbId); _.tbLeft.style.textAlign = _.obj.style.textAlign; //判断是否出现横向滚动条,若出现,高度减去滚动条高度 16px var sw = _.obj.offsetWidth > _.box.offsetWidth ? 0 : 0; _.divLeft.style.height = (_.box.offsetHeight - sw) + 'px'; var hasLeft = false; for(var i = 0, rows = _.obj.rows.length; i < rows; i++) { var row = _.tbLeft.insertRow(_.tbLeft.rows.length); row.style.cssText = _.obj.rows[i].style.cssText; for(var j = 0; j < _.config.cols; j++) { var cell = _.obj.rows[i].cells[j]; if(cell != null) { row.appendChild(cell.cloneNode(true)); cell.style.cssText = _.obj.rows[i].cells[j].style.cssText; hasLeft = true; } } } return hasLeft; }; oFixedTable.prototype.buildTopLeft = function() { var _ = this; var strDivId = _.id + '_div_top_left'; var strTbId = _.id + '_tb_top_left'; var div = document.createElement('div'); div.id = strDivId; div.style.cssText = 'position:absolute;overflow:hidden;z-index:' + (_.config.zindex + 2) + ';box-shadow: #dddddd 2px 0px 2px;width: 2rem;'; div.innerHTML = '<table id="' + strTbId + '" cellpadding="0" cellspacing="0" style="background:' + _.config.background + ';"></table>'; _.box.insertBefore(div, _.obj); var tbTopLeft = document.getElementById(strTbId); tbTopLeft.style.textAlign = _.obj.style.textAlign; for(var i = 0; i < _.config.rows; i++) { var row = tbTopLeft.insertRow(tbTopLeft.rows.length); row.style.cssText = _.obj.rows[i].style.cssText; for(var j = 0; j < _.config.cols; j++) { var cell = _.obj.rows[i].cells[j]; if(cell != null) { row.appendChild(cell.cloneNode(true)); cell.style.cssText = _.obj.rows[i].cells[j].style.cssText; hasLeft = true; } } } }; export default{ // 接收父组件传过来的参数 props: ['tableRows', 'gridColumns', 'thead', 'store', 'height', 'singleData'], // 监控 watch: { 'tableRows': function (val) { var self = this // 明星店铺页面时动态调整店铺名所在列的宽度s if (self.store) { document.querySelectorAll('table td:nth-child(3)')[0].style.width = 3 + 'rem' document.querySelectorAll('table th:nth-child(3)')[0].style.width = 3 + 'rem' } var length = self.gridColumns.length document.getElementById('tbTest1').style.width = 2 * length + 'rem' setTimeout(function () { if (self.singleData) { document.getElementById('ofix1_tb_left').classList.add('ofix1_tb_left') } document.querySelectorAll('#ofix1_tb_left td')[0].style.width = 2 + 'rem' var tbObj = document.getElementById('ofix1_tb_header') tbObj.addEventListener('click',function (event) { if(event.target.tagName === 'TH'){ self.sortBy(event.target.innerText, event) } }) }, 101) } }, data: function() { var sortOrders = {} this.gridColumns.forEach(function (key) { sortOrders[key] = 1 }) return { sortKey: '', filterUrl: './static/img/indus/filter1.png', sortOrders: sortOrders } }, methods: { sortBykey: function (a, b) { return parseFloat(a[this.sortKey]) - parseFloat(b[this.sortKey]) console.log('11111111111') }, sortBy: function (key, event) { // 每一次排序之前所有的图片重置 var imgDom = document.querySelectorAll('#ofix1_tb_header th img') for (var x = 0; x < imgDom.length; x++) { imgDom[x].setAttribute('src', './static/img/indus/filter1.png') } // 排序 var activeTheadIndex = 0 for (var i = 0; i < this.thead.length; i++) { if (this.thead[i] === key) { activeTheadIndex = i } } this.sortKey = this.gridColumns[activeTheadIndex] this.sortOrders[this.gridColumns[activeTheadIndex]] = this.sortOrders[this.gridColumns[activeTheadIndex]] * -1 // 排序时同步改变标识图片 if (this.sortOrders[this.gridColumns[activeTheadIndex]] > 0) { event.target.getElementsByTagName('img')[0].setAttribute('src', './static/img/indus/filter2.png') } else { event.target.getElementsByTagName('img')[0].setAttribute('src', './static/img/indus/filter3.png') } // 排序时同步改变左边第一列的内容 setTimeout(function(){ var tdDom = document.querySelectorAll('#tbTest1 tr td:nth-child(1)') var tdDomLeft = document.querySelectorAll('#ofix1_tb_left td') for (var y = 0; y < tdDom.length; y++) { tdDomLeft[y].innerHTML = tdDom[y].innerHTML } },0) } }, filters: { numberFilter: function (value) { if (value == 0) { return '0' } else if (!value) { return '/' } else { return value } } }, components: { }, ready: function() { var ofix1 = new oFixedTable('ofix1', document.getElementById('tbTest1'), { rows: 1, cols: 1 }) }, created () { } } </script> <style lang="scss" scoped> #divBox1{ overflow:auto; width:100%; font-size: 0.28rem; } #ofix1_div_left{ box-shadow: #dddddd 2px 0px 2px; width: 2rem; } table { table-layout : fixed; } table td, table th { width: 2rem; line-height: 1rem; height: 1rem; padding: 0; color: #999999; overflow: hidden; white-space: nowrap; /*vertical-align: middle;*/ } table th{ background: rgba(188,219,255,0.4); color: #999; font-size: .28rem; font-weight: normal; } table th:nth-child(1){ box-shadow: #dddddd 2px 0px 0px; } .ofix1_tb_left tr td:nth-child(1){ /*display: inline-block;*/ text-align: left; } #ofix1_div_top_left{ box-shadow: #dddddd 2px 0px 2px; } #tbTest1 tr td:nth-child(1){ box-shadow: #dddddd 2px 0px 0px; } #tbheader td { background: #fff; } </style>
父组件调用实例:
<template> <table-locked :table-rows="tableData" :grid-columns="gridColumns" :thead="thead" :height="height"> </table-locked> </template>
import TableLocked from '../../common/TableLocked.vue' export default{ components: {TableLocked}, data () { data.gridColumns = ['brand', 'product_count', 'averagePrice', 'sales', 'huang_sale_per', 'sale_per', 'sales_amount', 'huang_sale_amount_per', 'sales_amount_per', 'score_num', 'scort_good_per'] data.thead = ['品类', '产品种类', '均价', '销量', '销量环比', '销量占比', '销额(万元)', '销额环比', '销额占比', '评论总数', '好评率'] } }