Complete step record of Vue encapsulation of general table components

Complete step record of Vue encapsulation of general table components

Preface

As the business develops and the functions increase, we find that many pages have similar functions. Here are a few common examples: drop-down menus with multiple selections, dialog boxes with input, date pickers, etc. So we will try to extract these common functions into common components so that they can be used in different pages or businesses.

Why do we need to encapsulate the table component?

The tables in the background management system are used frequently, which reduces the business code about the tables and facilitates unified modification and maintenance in the later stage. For example, when displaying table contents, ellipsis is used to display the contents outside the cell.

For most backend management systems, the display of data tables is similar. Since I don’t want to write duplicate code, I choose to encapsulate the general table component to free my hands. If your table has a column that is not a simple DOM element, such as a switch button, you can pass in a render function to achieve your goal.

Step 1: Define common components

<!-- pro-table.vue -->
<template>
  <div>
    <el-table
      :data="tableData"
      style="width: 100%"
      :stripe="tableTitle.stripe"
      :border="tableTitle.border"
      :fit="tableTitle.fit"
      :highlight-current-row="tableTitle.highlightCurrentRow"
      @selection-change="handleSelectionChange">
      <!--First column of the table-->
      <el-table-column
        :type="firstTableCol.type"
        :width="firstTableCol.width"
        v-if="firstTableCol.select"
      >
      </el-table-column>
      <!--Other columns in the table-->
      <el-table-column v-for="(value,index) in tableCol" :key="index"
                       :prop="value.prop"
                       :label="value.label"
                       :width="value.width || 180">
        <template slot-scope="scope">
          <template v-if="!value.render">
            <template v-if="value.formatter">
              {{ value.formatter(scope.row, value) }}
            </template>
            <template v-else-if="value.getImgurl">
              <el-image :src="value.getImgurl(scope.row, value)" style="width: 70px; height: 70px"
                        :preview-src-list="value.previewSrcList ? value.previewSrcList(scope.row, value) : value.getImgurl(scope.row, value).split(',')"/>
            </template>
            <template v-else>
              {{ scope.row[value.prop] }}
            </template>
          </template>
          <!--Extended DOM-->
          <template v-else>
            <Table :key="`cus${index}`" :render="value.render" :param="scope.row"></Table>
          </template>
        </template>
      </el-table-column>
      <!--Basic operations-->
      <el-table-column label="operation">
        <template slot-scope="scope">
          <el-button type="text" v-for="(value,index) in operator" @click="value.click(scope.row, value)" :key="index">
            {{ value.text }}
          </el-button>
        </template>
      </el-table-column>
    </el-table>
    <!--Pagination plugin-->
    <el-pagination
      v-show="total>0"
      :total="total"
      :page-size.sync="pageSize"
      :current-page.sync="currentPage"
      :page-sizes="[10, 20, 30, 50]"
      layout="total, sizes, prev, pager, next, jumper"
      @current-change="handleCurrentChange"
      @size-change="handleSizeChange"
      v-bind="$attrs">
    </el-pagination>
  </div>
</template>

<script>
// render function import Table from './table'
export default {
  components: {Table},
  props: {
    tableTitle: {
      type: Object,
      default: {
        stripe: false,
        border: false,
        fit: true,
        highlightCurrentRow: false
      }
    },
    firstTableCol: {
      type: Object,
      default: {
        select: false,
        width: 55,
        type: 'selection'
      }
    },
    tableCol: {
      type: Array,
      default: []
    },
    tableData: {
      type: Array,
      default: []
    },
    operator:
      type: Array,
      default: []
    },
    total:
      type: Number,
      default: 0
    },
    page: {
      type: Number,
      default: 1
    },
    limit: {
      type: Number,
      default: 10
    },
    autoScroll: {
      type: Boolean,
      default: true
    }
  },
  computed: {
    currentPage: {
      get () {
        return this.page
      },
      set (val) {
        this.$emit('update:page', val)
      }
    },
    pageSize: {
      get () {
        return this.limit
      },
      set (val) {
        this.$emit('update:limit', val)
      }
    }
  },
  data () {
    return {
    }
  },
  methods: {
    // Listen to the table selection box handleSelectionChange (selection) {
      //Call the handleSelectionChange method corresponding to the parent component
      this.$emit('handleSelectionChange', selection)
    },
    // How many records per page should be monitored (limit)
    handleSizeChange (limit) {
      this.$emit('pagination', {page: this.currentPage, limit: limit})
      if (this.autoScroll) {
        scrollTo(0, 800)
      }
    },
    // Monitor the current page (page)
    handleCurrentChange (page) {
      this.$emit('pagination', {page: page, limit: this.pageSize})
      if (this.autoScroll) {
        scrollTo(0, 800)
      }
    }
  }
}
</script>
<style scoped>
</style>

Step 2: Render communication between parent component and child component

In order to make the parent component render function take effect in the child component, we need to define a render function and reference it in the child component.

// table.js
export default {
  props: {
    render: {
      type: Function
    },
    param: {
      type: Object
    }
  },
  render(h) {
    return this.render(h, this.param)
  }
}

Step 3: Using Components

<template>
  <div>
    <!--
        @Custom event="parent component method", in the child component, this.$emit('custom event name') triggers the parent component event.
        ref="proTable", marked on the subcomponent, pointing to the subcomponent instance -->
    <proTable ref="proTable" :tableTitle="tableTitle" :tableCol="tableCol" :tableData="tableData" :operator="operator"
        :firstTableCol="firstTableCol"
        @handleSelectionChange="handleSelectionChange"
        :total="total" :page.sync="queryParams.page" :limit.sync="queryParams.limit" @pagination="getList"/>

  </div>
</template>

<script>
import proTable from './pro-table'

export default {
  components:
    proTable
  },
  data() {
    return {
      queryParams: {
        page: 1,
        limit: 10,
      },
      type: 'success',
      total: 50,
      // Setting table attributes in element-ui tableTitle: {
        'stripe': true,
        "highlightCurrentRow": true
      },
      // Set the table column tableCol: [
        { prop:'date',label:'date'},
        { prop:'name',label:'Name'},
        { prop:'address',label:'Address',width: 300},
        { prop:'src',label:'Picture',  
        getImgurl: (row, col, cellValue) => { return this.getImgurl(row)}, 
        previewSrcList: (row, col, cellValue) => {return this.listImgUrl(row)}},
        { prop:'sex', label:'Gender',  
        formatter: (row, col, cellValue) => {return this.sexFormatter(row)}},
        { prop:'src',label:'Picture',  
        getImgurl: (row, col, cellValue) => { return this.getImgurl(row)}},
        { prop:'text',label:'function', render: (h, params) => {return this.render(h, params)}}
      ],
      // Basic table operations operator: [
        {'text':'Details', click: (row, col, cellValue) => {return this.getInfo(row)}},
        {'text':'Delete', click: (row, col, cellValue) => {return this.delInfo(row)}},
        {'text':'Edit', click: (row, col, cellValue) => {return this.editInfo(row)}},
      ],
      // Simulation data tableData: [
        {
          date: '2016-05-02',
          name: 'Wang Xiaohu',
          address: 'No. 1518, Jinshajiang Road, Putuo District, Shanghai',
          sex: 0,
          img:'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fpic2.zhimg.com%2F50%2Fv2-193cbb243dc14d3a016caaa54ba02837_hd.jpg&refer=http%3A%2F%2Fpic2.zhimg.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1628435704&t=deb5584cb9ff53fe6977f14a5e0755bb'
        }, {
          date: '2016-05-04',
          name: 'Wang Xiaohu',
          address: 'No. 1517, Jinshajiang Road, Putuo District, Shanghai',
          sex: 1,
          img:'https://pic1.zhimg.com/80/v2-894ab624807fd4cfa33dd4e42cc90ac8_720w.jpg?source=1940ef5c'
        }, {
          date: '2016-05-01',
          name: 'Wang Xiaohu',
          address: 'No. 1519, Jinshajiang Road, Putuo District, Shanghai',
          sex: 0,
          img:'xx.jpg'
        }, {
          date: '2016-05-03',
          name: 'Wang Xiaohu',
          address: 'No. 1516, Jinshajiang Road, Putuo District, Shanghai',
          sex: 1,
          img:'xx.jpg'
        }],
      firstTableCol: {
        'select': true,
        'type': 'selection'
      }
    }
  },
  methods: {
    getInfo(val) {
      // Trigger the parent method console.log("Get details",val)
    },
    delInfo(val) {
      // Trigger the parent method console.log("delete information",val)
    },
    editInfo(val) {
      // Trigger parent method console.log("Edit information",val)
    },
    getImgurl(val) {
      console.log(val.img)
      return val.img
    },
    sexFormatter(val) {
      return val.sex === 0 ? 'male' : 'female'
    },
    handleSelectionChange(val) {
      console.log("listen selection box",val)
    },
    getList(queryParams) {
      console.log("parent method",queryParams)
    },
    listImgUrl() {
      let array = [];
      array.push("https://pic1.zhimg.com/80/v2-894ab624807fd4cfa33dd4e42cc90ac8_720w.jpg?source=1940ef5c");
      array.push("https://cdn.pixabay.com/photo/2021/07/01/21/20/girl-6380331_960_720.jpg");
      return array;
    },
    render(h, params) {
      return h('span', null, 'I am a render component')
    }
  }
}
</script>

Summarize

In the page that references the component, we can add methods to each table column, and we can also add custom methods to edit, delete, and details to fully achieve customization. You can also customize the render function. The effect diagram is as follows:

This is the end of this article about Vue encapsulation of universal table components. For more relevant Vue encapsulation of universal table components, please search for previous articles on 123WORDPRESS.COM or continue to browse the following related articles. I hope everyone will support 123WORDPRESS.COM in the future!

You may also be interested in:
  • Vue elementui implements the example code of the search bar public component encapsulation
  • Detailed explanation of how to encapsulate your own component in vue element-ui
  • Detailed analysis of the usage and application scenarios of slots in Vue
  • How to use vue slot to encapsulate common components in vue

<<:  MySQL trigger definition and usage simple example

>>:  How to build Git service based on http protocol on VMware+centOS 8

Recommend

Why MySQL database avoids NULL as much as possible

Many tables in MySQL contain columns that can be ...

uni-app WeChat applet authorization login implementation steps

Table of contents 1. Application and configuratio...

MySQL helps you understand index pushdown in seconds

Table of contents 1. The principle of index push-...

Detailed explanation of MySQL transaction isolation level and MVCC

Table of contents Transaction Isolation Level Pro...

Detailed explanation of Vue form binding and components

Table of contents 1. What is two-way data binding...

How to use firewall iptables strategy to forward ports on Linux servers

Forwarding between two different servers Enable p...

Detailed explanation of mysql trigger example

Table of contents What is a trigger Create a trig...

How to use vue-cli to create a project and package it with webpack

1. Prepare the environment (download nodejs and s...

How to reset your Linux password if lost

1. The startup menu is to move the cursor to the ...

Echarts tutorial on how to implement tree charts

Treemaps are mainly used to visualize tree-like d...

HeidiSQL tool to export and import MySQL data

Sometimes, in order to facilitate the export and ...

The easiest way to reset mysql root password

My mysql version is MYSQL V5.7.9, please use the ...