Skip to content

element的表格如何实现列显示与隐藏的控制?

通过 v-if 实现

初级开发通常给每个 el-table-column 绑定一个 v-if

但是有时会导致列内容错乱/混乱/冲突显示,此时应该给表格的每个 el-table-column 加上唯一的 key

但是最好给列加入的key是一个唯一固定值,比如 key="1" ,而不是随机数,比如 :key="Math.random()" 会导致列隐藏/显示时的表格的闪烁/抖动。

很明显这样的方式非常费时费力,每一个列都需要添加 v-if 和唯一的key,成本过高。下面介绍使用JSON二次封装封装element表格的方式来实现对列显示/隐藏的控制。

通过JSON二次封装表格实现

先创一个建名为FileTable的组件,然后我们定义需要父组件传的值

html
<script>
export default {
    props: {
        tableData: { // 父组件传递过来的表格数据
            type: Array,
            default: () => {
                return []
            }
        },
        tableLabel: { // 父组件传递过来的表头数据
            type: Array,
            default: () => {
                return []
            }
        }
    },
}
</script>
<script>
export default {
    props: {
        tableData: { // 父组件传递过来的表格数据
            type: Array,
            default: () => {
                return []
            }
        },
        tableLabel: { // 父组件传递过来的表头数据
            type: Array,
            default: () => {
                return []
            }
        }
    },
}
</script>

引入Element官方的el-table组件:

  1. 绑定父组件传入的表格数据
  2. 循环父组件传入的表头数据 来生成el-table-column列
  3. v-if绑定show属性控制该列是否显示
html
<el-table
      ref="filterTable"
      //data绑定父组件传入的表格数据
      :data="tableData"
      :max-height="tableHeight"
      size="small"
      row-class-name="row"
      cell-class-name="column"
      :highlight-current-row="true"
      fit
      :header-cell-style="headerStyle"
      :cell-style="{'text-align':'center'}"
      @cell-click="clickRow"
      @row-dblclick="rowdblclick"
      @selection-change="SelectChange"
    >
      <el-table-column :show-overflow-tooltip="true" sortable type="selection" width="45" />
      <el-table-column :show-overflow-tooltip="true" sortable type="index" :index="indexMethod" :cell-style="{'text-align':'center'}" style="text-align:center" label="ID" width="85"></el-table-column>
      <!-- 循环父组件传入的表头数据 -->
      <template v-for="(item, index) in tableLabel">
        <el-table-column
        //v-if控制该列是否显示
          v-if="item.show"
          :key="index"
          :show-overflow-tooltip="true"
          sortable
          :prop="item.prop"
          :width="item.width"
          :label="item.label"
        />
      </template>
</el-table>
<el-table
      ref="filterTable"
      //data绑定父组件传入的表格数据
      :data="tableData"
      :max-height="tableHeight"
      size="small"
      row-class-name="row"
      cell-class-name="column"
      :highlight-current-row="true"
      fit
      :header-cell-style="headerStyle"
      :cell-style="{'text-align':'center'}"
      @cell-click="clickRow"
      @row-dblclick="rowdblclick"
      @selection-change="SelectChange"
    >
      <el-table-column :show-overflow-tooltip="true" sortable type="selection" width="45" />
      <el-table-column :show-overflow-tooltip="true" sortable type="index" :index="indexMethod" :cell-style="{'text-align':'center'}" style="text-align:center" label="ID" width="85"></el-table-column>
      <!-- 循环父组件传入的表头数据 -->
      <template v-for="(item, index) in tableLabel">
        <el-table-column
        //v-if控制该列是否显示
          v-if="item.show"
          :key="index"
          :show-overflow-tooltip="true"
          sortable
          :prop="item.prop"
          :width="item.width"
          :label="item.label"
        />
      </template>
</el-table>

然后通过this.$emit绑定父组件自定义事件,子组件来触发(根据个人需求定义)

html
<script>
export default {
methods: {
    // 单击选中某一行选框
    clickRow(row) {
      this.$refs.filterTable.toggleRowSelection(row)
      this.$emit('clickRow', row)
    },
    // 双击选中某一行
    rowdblclick(row) {
      this.$emit('rowdblclick', row)
    },
    // 选中一行或者多行数据
    SelectChange(val) {
      this.$emit('SelectChange', val)
    },
    // 翻页序号连续
    indexMethod(index) {
      return (index + 1)
    }
  }
}
</script>
<script>
export default {
methods: {
    // 单击选中某一行选框
    clickRow(row) {
      this.$refs.filterTable.toggleRowSelection(row)
      this.$emit('clickRow', row)
    },
    // 双击选中某一行
    rowdblclick(row) {
      this.$emit('rowdblclick', row)
    },
    // 选中一行或者多行数据
    SelectChange(val) {
      this.$emit('SelectChange', val)
    },
    // 翻页序号连续
    indexMethod(index) {
      return (index + 1)
    }
  }
}
</script>

父组件传值表头数据的格式:

js
tableLabel: [
        { label: 'MerchantPaymentDesc', width: '', prop: 'merchantPaymentDesc', show: true },
        { label: 'storeDesc', width: '', prop: 'storeDesc', show: true },
        { label: 'TransTime', width: '', prop: 'transTime', show: true },
        { label: 'PayBarcode', width: '', prop: 'payBarcode', show: true },
        { label: 'PlatformDesc', width: '', prop: 'platformDesc', show: true },
        { label: 'TransType', width: '', prop: 'transType', show: true },
        { label: 'ResultDesc', width: '', prop: 'resultDesc', show: true },
        { label: 'TotalAmount', width: '', prop: 'totalAmount', show: true },
        { label: 'RealPayAmount', width: '', prop: 'realPayAmount', show: true },
        { label: 'CreatedOn', width: '', prop: 'createdOn', show: true }
      ]
tableLabel: [
        { label: 'MerchantPaymentDesc', width: '', prop: 'merchantPaymentDesc', show: true },
        { label: 'storeDesc', width: '', prop: 'storeDesc', show: true },
        { label: 'TransTime', width: '', prop: 'transTime', show: true },
        { label: 'PayBarcode', width: '', prop: 'payBarcode', show: true },
        { label: 'PlatformDesc', width: '', prop: 'platformDesc', show: true },
        { label: 'TransType', width: '', prop: 'transType', show: true },
        { label: 'ResultDesc', width: '', prop: 'resultDesc', show: true },
        { label: 'TotalAmount', width: '', prop: 'totalAmount', show: true },
        { label: 'RealPayAmount', width: '', prop: 'realPayAmount', show: true },
        { label: 'CreatedOn', width: '', prop: 'createdOn', show: true }
      ]

到此为止,el-table的基本功能已经封装完毕了,但需求是动态来控制这些列的显示与隐藏

实现动态显示列

上面已经在el-table-column上绑定了show属性通过v-if来控制列的显示与隐藏,接下来只需要能够控制这些v-if绑定的show属性就可以了

我使用的的是el-checkbox来绑定和控制这些值

引入一个el-dialog弹出框 里面放上我们的el-checkbox v-for循环父组件传入的表头值 v-model绑定show属性

html
<el-dialog ref="dialog__wrapper" v-dialogDrag :title="$t('message.TableColumn')" :visible.sync="dialogFormVisible" :close-on-click-modal="false" :close-on-press-escape="false">
      <el-row :gutter="20">
        <el-col
          v-for="(item, index) in tableLabel"
          :key="index"
          :span="6"
          style="height:35px"
        >
          <el-checkbox v-model="item.show">{{ item.label }}</el-checkbox>
        </el-col>
      </el-row>
      <div slot="footer" class="dialog-footer">
        <el-button type="danger" size="mini" @click="dialogFormVisible = false">{{ $t('button.cancel') }}</el-button>
      </div>
</el-dialog>
<el-dialog ref="dialog__wrapper" v-dialogDrag :title="$t('message.TableColumn')" :visible.sync="dialogFormVisible" :close-on-click-modal="false" :close-on-press-escape="false">
      <el-row :gutter="20">
        <el-col
          v-for="(item, index) in tableLabel"
          :key="index"
          :span="6"
          style="height:35px"
        >
          <el-checkbox v-model="item.show">{{ item.label }}</el-checkbox>
        </el-col>
      </el-row>
      <div slot="footer" class="dialog-footer">
        <el-button type="danger" size="mini" @click="dialogFormVisible = false">{{ $t('button.cancel') }}</el-button>
      </div>
</el-dialog>

在列表上嵌入一个按钮来触发弹出该dialog

html
<el-table
      ref="filterTable"
      :data="tableData"
      :max-height="tableHeight"
      size="small"
      row-class-name="row"
      cell-class-name="column"
      :highlight-current-row="true"
      fit
      :header-cell-style="headerStyle"
      :cell-style="{'text-align':'center'}"
      @cell-click="clickRow"
      @row-dblclick="rowdblclick"
      @selection-change="SelectChange"
    >
      <el-table-column :show-overflow-tooltip="true" sortable type="selection" width="45" />
      <el-table-column :show-overflow-tooltip="true" sortable type="index" :index="indexMethod" :cell-style="{'text-align':'center'}" style="text-align:center" label="ID" width="85">
      <!-- //这个地方是新添加的按钮 -->
        <template slot="header">
          <el-button size="mini" type="" class="el-icon-s-operation" click @click="dialogFormVisible=true" />
        </template>
      </el-table-column>
      <template v-for="(item, index) in tableLabel">
        <el-table-column
          v-if="item.show"
          :key="index"
          :show-overflow-tooltip="true"
          sortable
          :prop="item.prop"
          :width="item.width"
          :label="item.label"
        />
      </template>
    </el-table>
<el-table
      ref="filterTable"
      :data="tableData"
      :max-height="tableHeight"
      size="small"
      row-class-name="row"
      cell-class-name="column"
      :highlight-current-row="true"
      fit
      :header-cell-style="headerStyle"
      :cell-style="{'text-align':'center'}"
      @cell-click="clickRow"
      @row-dblclick="rowdblclick"
      @selection-change="SelectChange"
    >
      <el-table-column :show-overflow-tooltip="true" sortable type="selection" width="45" />
      <el-table-column :show-overflow-tooltip="true" sortable type="index" :index="indexMethod" :cell-style="{'text-align':'center'}" style="text-align:center" label="ID" width="85">
      <!-- //这个地方是新添加的按钮 -->
        <template slot="header">
          <el-button size="mini" type="" class="el-icon-s-operation" click @click="dialogFormVisible=true" />
        </template>
      </el-table-column>
      <template v-for="(item, index) in tableLabel">
        <el-table-column
          v-if="item.show"
          :key="index"
          :show-overflow-tooltip="true"
          sortable
          :prop="item.prop"
          :width="item.width"
          :label="item.label"
        />
      </template>
    </el-table>

大功告成,接下来我们在父组件引入该组件

js
import FileTable from '@/components/FileTable/FileTable.vue'
export default {
  components: { FileTable }
}
import FileTable from '@/components/FileTable/FileTable.vue'
export default {
  components: { FileTable }
}

页面上使用,绑定上我们需要的值,一行搞定~

html
<FileTable id="out-table" :table-data="tableData" :table-label="tableLabel" @rowdblclick="rowdblclick" @SelectChange="SelectChange" />
<FileTable id="out-table" :table-data="tableData" :table-label="tableLabel" @rowdblclick="rowdblclick" @SelectChange="SelectChange" />