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的大小改变。

    1.gif

    在线运行: meteor199.github.io/my-demo/vue…
    demo源码:github.com/meteor199/m…

    分类:
    前端