iview 設置table高度100%的一種方法

運行環境

iview版本: 3.5.0-rc.1 
vue版本: 2.6.10 

問題

image.png
iview中的table是不能直接佔滿父容器的,它的 height 屬性必須設置成一個固定值。假如直接給table設置style爲
height:100% ,它的滾動條會丟失。
image.png
image.png

但是很多時候我們需要table佔滿父容器,需要表頭和頁腳進行固定,只讓中間數據部分進行滾動。

chrome 中打開 Elements ,可以看到 iview使用了 object 標籤。 html中一般只能監聽 window 的 resize 事件,而無法直接監聽 div 等元素大小改變的,但是有時可以插入一個 object 標籤來間接監聽 div 大小的改變。它這裏是否用了object 來監聽大小改變呢?
image.png
打開 iview的源碼 ,看到它果真是用來監聽大小改變的,但是它監聽改變後只處理了 width ,沒有處理 height 。所以這裏我們可以包裝一下 Table,監聽它的resize事件,然後動態設置 height屬性,來使 Table支持 height:100% 。

解決方法

iview是用的 element-resize-detector 庫來監聽外層div的改變,並且把將這個庫設置爲組件的全局變量。所以我們也可以使用這個全局變量來監聽外層div大小,然後動態設置 height。
image.png

創建一個 FillTable的組件,用來包裝 Table, FillTable.js 的源碼如下:

FillTable

import { Table } from 'iview';
export default {
  name: 'fill-table',
  render(h) {
    /**傳遞prop */
    const tableProps = {};
    for (let prop in Table.props) {
      tableProps[prop] = this[prop];
    }
    tableProps.height = this.tableHeight;

    return h(Table, {
      props: tableProps,
      ref: 'table',
      /**傳遞事件 */
      on: this.$listeners,
      /**傳遞作用域插槽 */
      scopedSlots: this.$scopedSlots,
      /**傳遞插槽 */
      slot: this.$slot
    });
  },
  props: (() => {
    var props = {};
    Object.assign(props, Table.props, {
      height: {
        type: Number
      },
      /** 默認佔滿父容器 */
      fill: {
        type: Boolean,
        default: true
      }
    });
    return props;
  })(),
  watch: {
    height: {
      handler() {
        this.tableHeight = this.height;
      }
    },
    immediate: true
  },
  data() {
    // 自帶屬性值
    return {
      tableHeight: 0
    };
  },
  methods: {
    handleIViewTableResize(el) {
      this.tableHeight = el.offsetHeight;
    },
    getTableRef() {
      return this.$refs.table;
    }
  },
  mounted() {
    if (this.fill) {
      // this.$nextTick(() => {
        this.getTableRef().observer.listenTo(this.$el, this.handleIViewTableResize);
      // });
    }
    /**傳遞方法 */
    for (let method in Table.methods) {
      this[method] = (...args) => Table.methods[method].apply(this.getTableRef(), args);
    }
  },

  beforeDestroy() {
    if (this.fill) {
      this.getTableRef().observer.removeListener(this.$el, this.handleIViewTableResize);
    }
  }
};

使用

使用時和iview中的table的屬性和方法基本一致,只有以下地方需要注意:

  • 添加 v-bind:fill屬性,默認值是true,爲true請不要再設置v-bind:height。設置爲true,則支持 table的style中的 height:100% 的樣式。
  • 假如需要 v-bind:height=固定值 ,則需要 v-bind:fill="false" 
  • 假如需要找到table組件實例,請使用 getTableRef 方法,如 this.refs.table.getTableRef() 。
      <FillTable
        ref="table"
        style="width:100%;height:100%"
        :columns="columns1"
        :data="data1"
        :fill="true"
      >
        <template #name="{ row }">
          <strong>{{ row.name }}--ddd</strong>
        </template>
      </FillTable>

注意事項

由於是侵入性修改,假如iview改了源碼,比如將observer的全局字段去除了,則這裏就會出錯。這時可以直接引用 element-resize-detector 來監聽Table的大小改變。

demo

1.gif
在線運行: https://meteor199.github.io/my-demo/vue/iview-fill-table/dist/index.html
demo源碼:https://github.com/meteor199/my-demo/tree/master/vue/iview-fill-table

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章