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

Detailed steps for installing and configuring MySQL 8.0 on CentOS 7.4 64-bit

Step 1: Get the MySQL YUM source Go to the MySQL ...

Press Enter to automatically submit the form. Unexpected discovery

Copy code The code is as follows: <!DOCTYPE ht...

Summary of several principles that should be followed in HTML page output

1. DOCTYPE is indispensable. The browser determin...

How to modify server uuid in Mysql

Source of the problem: If the slave server is the...

How to view and modify the time zone in MySQL

Today I found that a program inserted an incorrec...

JavaScript to implement retractable secondary menu

The specific code for implementing the retractabl...

Solution to slow network request in docker container

Several problems were discovered during the use o...

Detailed explanation of type protection in TypeScript

Table of contents Overview Type Assertions in syn...

Perfect solution to MySQL common insufficient memory startup failure

1. If MySQL is not started successfully, check th...

Example of integrating Kafka with Nginx

background nginx-kafka-module is a plug-in for ng...

Solutions to MySql crash and service failure to start

I have been in contact with PHP for so long, but ...

MySQL master-slave replication configuration process

Main library configuration 1. Configure mysql vim...

How to use CSS to pull down a small image to view a large image and information

Today I will talk about a CSS special effect of h...

Mysql stores tree structure through Adjacency List (adjacency list)

The following content introduces the process and ...

MySQL installation and configuration tutorial for Mac

This article shares the MySQL installation tutori...