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

A brief discussion on the characteristics of CSS float

This article introduces the characteristics of CS...

Setting up a proxy server using nginx

Nginx can use its reverse proxy function to imple...

Vue realizes the sliding cross effect of the ball

This article example shares the specific code of ...

A brief discussion on how to learn JS step by step

Table of contents Overview 1. Clearly understand ...

How to write asynchronous tasks in modern JavaScript

Preface In this article, we'll explore the ev...

Binary installation of mysql 5.7.23 under CentOS7

The installation information on the Internet is u...

Introduction to Vue3 Composition API

Table of contents Overview Example Why is it need...

mySql SQL query operation on statistical quantity

I won't say much nonsense, let's just loo...

Docker image access to local elasticsearch port operation

Using the image service deployed by docker stack,...

Web Design: Web Music Implementation Techniques

<br />When inserting music into a web page, ...

DockerToolBox file mounting implementation code

When using docker, you may find that the file can...

Detailed explanation of the use of filter properties in CSS

The filter attribute defines the visual effect of...

How to set the style of ordered and unordered list items in CSS

In an unordered list ul>li, the symbol of an u...