牛骨文教育服务平台(让学习变的简单)
博文笔记

Vue 固定头 固定列 点击表头可排序 表格组件

创建时间:2016-11-25 投稿人: 浏览次数:124

原理是将原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 = ["品类", "产品种类", "均价", "销量", "销量环比", "销量占比", "销额(万元)", "销额环比", "销额占比", "评论总数", "好评率"]
    }
}


声明:该文观点仅代表作者本人,牛骨文系教育信息发布平台,牛骨文仅提供信息存储空间服务。