Working overtime until midnight, looking around no one to go; Leave tomorrow night at 8:00 sharp. Whoever doesn’t clock in is a dog.

Used element – the UI form students should have such experience, do a simple form is relatively easy, but if this table contains the top of the button, and paging, even contains a line edit, the development work has increased exponentially, especially in the development and management system, form one by one to develop, is a waste of time, There is no personal improvement yet. Today, xiaobian has brought its own package of tables, so that you can use JSON to easily generate tables.

This article focuses on encapsulation ideas and core code descriptions. For the complete code, visit github.com/snowzijun/v… , if you feel useful, please give xiaobian a star, each of your stars is to support xiaobian, the current function is relatively simple, the warehouse will continue to update. At the same time, you can also search wechat [front-end some play] public number, communicate with xiaobian.

Form demand

General management systems have the following requirements for forms

  1. Can be paginated (requires a page bar)
  2. Multiple options (table with check boxes)
  3. Need some action buttons (add, delete, etc.) at the top
  4. The table has action buttons at the end of each row
  5. Table rows can be edited

A sample table is shown below


If we were to use the components provided by Element-UI directly, the following would be used to develop such a table

  1. You need to use the slot function of the table to develop buttons for each row
  2. You need to adjust the layout of the top button, table, and page bar with styles
  3. You need to listen for paginated events and then refresh the table data
  4. The top button or action button calls the API provided by the table if it needs to retrieve table data
  5. For the need for line editing, you also need to render the line editing content through the slot, and control the line editing switch

Not only is it a hassle to develop tables, but there is also a need for teamwork, and if everyone implements the tables differently, it can be costly to maintain later. So what to do?

Project installation

Installing a plug-in

In a project that uses Element-UI, you can install it with the following command

npm install vue-elementui-table -S
Copy the code

For use in projects

Add the following code to main.js

import ZjTable from 'vue-elementui-table'

Vue.use(ZjTable)
Copy the code

It can then be used as described below

Form the configuration

In order to meet the rapid development needs of the team, xiaobian has encapsulated the requirements mentioned above, and then when using, developers only need to configure some JSON to complete the development of the above functions.

Basic configuration

A basic table contains data and column information, so how do you configure it with encapsulated tables?

<template> <zj-table :columns="columns" :data="data" :pagination="false" /> </template> <script> export default { data() {return {// Table column information, each element of the array represents a field, can use all the attributes of the Element column attribute, the following is only an example of columns: object. freeze([{// table header text label: Prop: 'name', {label: 'gender ', prop: Formatter (row, column, cellValue) {return cellValue === 1? 'male' : 'female'}}, {label: 'age, prop:' age '}]), data: [{name: 'zijun, sex: 1, age: 18}]}}} < / script >Copy the code

With the above configuration, you can complete the development of a basic table. The complete code can be found at github.com/snowzijun/v… , the effect is shown in the figure below


The table displays checkboxes by default and can be turned off by configuring the Selectable property

Add paging

Simple tables have little difference in development effort between wrapped and unwrapped, so we continue to add pagination to the table

<template> <! Sync Automatically synchronizes the page number when the page number changes Page-size. sync Number of pages per page Total Number of pages height="auto" Height :auto, If not specified, the table will remain full of the parent container, and the table header will remain fixed. @page-change does not follow the scroll bar to scroll @pagesize currentPage, <zj-table v-loading="loading" :columns="columns" :data="data" :current-page.sync="currentPage" :page-size.sync="pageSize" :total="total" height="auto" @page-change="$_handlePageChange" /> </template> <script> export Default {data() {return {columns: object.freeze ([// Columns: object.freeze)), data: [], // currentPage: 1, // pageSize: 10, // total: 0, // Whether loading loading: false}}, created() {this.loadData()}, methods: LoadData () {this.loading = true setTimeout(() => {this.total = 40 const {currentPage, This. data = new Array(pageSize).fill({}).map((item, index)) => {return {name: ${currentPage + (index + 1) * 10} ', sex: Math. Random () > 0.5? 1:0, age: Math.floor(Math.random() * 100) } }) this.loading = false }, 1000) }, $_handlePageChange() {console.log(this.pagesize, this.currentPage); LoadData ()}}} </script>Copy the code

The full code can be found at github.com/snowzijun/v…

With encapsulation, the table will have its own pagination function, as shown in the code above. Next we continue to add buttons to the table


Add top button

You might have buttons on the table that add, delete, etc., so what do we do

<template> <zj-table :buttons="buttons" /> </template> <script> export default { data() { return { buttons: Object.freeze([{// id must have and is unique in the current button array id: 'add', text: 'new ', type: 'primary', icon:' el-icon-circles-plus ', click: This.$_handleAdd}, {id: 'delete', text: 'delete', // rows is the selected row in the table. If no rows are selected, the delete button is disabled. rows => !rows.length, click: this.$_handleRemove }, { id: 'auth', text: 'This button is displayed by permission ', // You can control whether the button displays before by returning true/false: (/** rows */) => {return true}}, // you can configure the drop-down button oh {id: 'dropdown', children: [{id: 'moveUp', children: [{id: 'moveUp', icon: 'el-icon-arrow-up', click: () = > {the console. The log (' move up ')}}, {id: 'moveDown, text:' down 'icon:' el - icon - arrow - down, disabled: Rows = >! Rows. Length, click: () = > {the console. The log (' down ')}}}}}]]), created () {}, the methods: {{/ / new $_handleAdd () enclosing $alert (' click the new button ')}, $_handleRemove(rows) {const ids = rows.map(({id}) => ID) this.$alert(' ${ids.join(',')} ') $_handleFollowAuthor() {}}} </script>Copy the code

You can add a normal button or a dropdown button at the top of the table. You can also use “before” to configure whether the button is displayed or “disabled” to configure whether the button is disabled. For the complete code, see github.com/snowzijun/v…

The following table can be configured using the above code, isn’t it easy?


You can have buttons at the top of the table, you can have buttons at the end of the line, so let’s see

Row operation button

We usually put some single-line buttons at the end of the line, such as edit, download, etc. How to configure buttons at the end of the line?

<template>
  <zj-table
    :columns="columns"
  />
</template>
<script> export default {  data() {  return {  columns: Object.freeze([  {  // Column widths can be specified, consistent with the native use of Element-UI  width: 220. label: 'name'. prop: 'name'  },  // The row edit button, which appears at the end of the table, automatically locks the right side  {  width: 180. label: 'operation'. // Specify end-of-line buttons by actions  actions: [  {  id: 'follow'. text: 'Follow the author'. click: this.$_handleFollowAuthor  },  {  id: 'edit'. text: 'edit'. // Before can be used to control whether the edit button is displayed  before(row) {  return row.age < 40  },  click: this.$_handleEdit  },  {  id: 'delete'. text: 'delete'. icon: 'el-icon-delete'. disabled(row) {  return row.sex === 0  },  // To get this, use the arrow function  click: (a)= > {  this.$alert('Girls are banned from deleting.')  }  }  ]  }  ])  }  },  methods: {  // Follow the author's public account  $_handleFollowAuthor() {  console.log('wechat search [front-end some play], this is the biggest support for xiaobian')  },  / * ** Row data* /  $_handleEdit(row, column) {  this.$alert('Click on the name [${row.name}】 the button on the line)  }  } } </script>  Copy the code

The row action button is frozen to the far right of the table and does not scroll with the scroll bar. See github.com/snowzijun/v for the complete code above.

The above code will do the following


Finally, let’s look at line editing

Line edit

For example, when I click the edit button at the end of the line, I can edit the user’s name and gender directly above the line. How to configure this?

<template>
  <zj-table
    ref="table"
    :columns="columns"
 :data="data"  /> </template> <script> export default {  data() {  return {  columns: Object.freeze([  {  label: 'name'. prop: 'name'. editable: true. field: {  componentType: 'input'. rules: [  {  required: true. message: 'Please enter your name'  }  ]  }  },  {  label: 'gender'. prop: 'sex'. // Format the table, the same as the table properties of element-UI  formatter(row, column, cellValue) {  return cellValue === '1' ? 'male' : 'woman'  },  editable: true. field: {  componentType: 'select'. options: [  {  label: 'male'. value: '1'  },  {  label: 'woman'. value: '0'  }  ]  }  },  {  label: 'age'. prop: 'age'. editable: true. field: {  componentType: 'number'  }  },  {  label: 'operation'. actions: [  {  id: 'edit'. text: 'edit'. // If the current row is edit-enabled, the edit button is not displayed  before: row= > {  return !this.editIds.includes(row.id)  },  click: this.$_handleEdit  },  {  id: 'save'. text: 'save'. // If editing is enabled on the current row, the save button is displayed  before: row= > {  return this.editIds.includes(row.id)  },  click: this.$_handleSave  }  ]  }  ]),  data: [  {  Row-key =" field name "; // Row-key =" field name "; // Row-key =" field name ";  id: '0'. name: 'zijun'. sex: '1'. age: 18  },  {  Row-key =" field name "; // Row-key =" field name "; // Row-key =" field name ";  id: '1'. name: Zijun '1'. sex: '0'. age: 18  } ]. editIds: []  }  },  methods: {  $_handleEdit(row) {  // Line editing can be enabled by calling startEditRow  this.$refs.table.startEditRow(row.id)  // Record the id of the line editing enabled  this.editIds.push(row.id)  },  $_handleSave(row) {  // When you click Save, end the row editing with endEditRow  this.$refs.table.endEditRow(row.id, (valid, result, oldRow) => {  // If there is a form validation, valid returns whether the validation succeeded  if (valid) {  console.log('Modified data', result)  console.log('Raw data', oldRow)  const index = this.editIds.findIndex(item= > item === row.id)  this.editIds.splice(index, 1)  } else {  // If the verification fails, the exception information of the first input box of the verification is returned  console.log(result)  this.$message.error(result.message)  }  })  }  } } </script>  Copy the code

Isn’t it nice to be able to edit lines without using slots? See the full code above at github.com/snowzijun/v…

The effect is shown below:


Other features

In addition to the above functions, tables can be configured with many other functions, such as

  1. Fields can be specified as linked columns, and columns need to be configuredlinkattribute
  2. You can customize top buttons, row action buttons, row fields, etc
  3. You can configure other content through the slot on the right of the button area
  4. Other, etc.

Form development Instructions

Now that we’ve seen what a wrapped table can do with the code example above, let’s look at how it works. The full code can be found at github.com/snowzijun/v…

Table layout

The entire table is encapsulated through JSX, which is more flexible to use. For the table we encapsulated, we can divide it into three parts vertically, namely the top button area, the middle table area and the bottom page area. How to achieve the layout of the three areas? The core code is as follows

render(h) {
    // Button area
    const toolbar = this.$_renderToolbar(h)
    // Table area
    const table = this.$_renderTable(h)
 // Paging area  const page = this.$_renderPage(h)   return (  <div class="zj-table" style={{ height: this.tableContainerHeight}} >  {toolbar}  {table}  {page}  </div>  )  } Copy the code

Render the corresponding regions with three render functions and then combine the three regions together.

Render table column

From the above explanation, we can divide the columns of the table into the following types

  1. Conventional column
  2. Line edit column
  3. Operation button column
  4. Slot columns
  5. Link column (documentation to follow)
  6. Nested columns (document later)
    $_renderColumns(h, columns) {
      // Whether the whole is sorted
      let sortable = this.sortable ? 'custom' : false
      return columns
        .filter(column= > {
 const { hidden } = column  if(hidden ! = =undefined) {  if (typeof hidden === 'function') {  return hidden({  columns,  column  })  }  return hidden  }  return true  })  .map(column= > {  const {  useSlot = false. // Actions is a non-empty array if there is an action button  actions = [],  // Whether columns are editable, for editable columns you need to dynamically enable editing  editable = false. // Whether there are nested columns  nests,  // Is it clickable  link = false  } = column  let newSortable = sortable  if(column.sortable ! = =undefined) {  newSortable = column.sortable ? 'custom' : false  }  column = { . column, sortable: newSortable  }  if (nests && nests.length) {  // Use nested columns  return this.$_renderNestColumn(h, column)  } else if (editable) {  // Use edit column  return this.$_renderEditColumn(h, column)  } else if (useSlot) {  // Use the slot column  return this.$_renderSlotColumn(h, column)  } else if (actions && actions.length > 0) {  // Use the action column  column.sortable = false  return this.$_renderActionColumn(h, column)  } else if (link) {  // Use link columns  return this.$_renderLinkColumn(h, column)  } else {  // Use the default column  return this.$_renderDefaultColumn(h, column)  }  })  }, Copy the code

Line edit column

Current form line edit support input, select, datepicker, TimeSelect, InputNumber components, such as specific rendering code as shown below

// Edit the cell
    $_renderEditCell(h, field) {
      const components = {
        input: Input,
        select: ZjSelect,
 date: DatePicker,  time: TimeSelect,  number: InputNumber  }  const componentType = field.componentType  const component = components[componentType]  if (component) {  return this.$_renderField(h, field, component)  } else if (componentType === 'custom') {  // If you want to customize, you can specify components by component  return this.$_renderField(h, field, field.component)  }  return this.$_renderField(h, field, Input)  },  $_renderField(h, field, Component) {  // Edit the id field of the row  const { rowId, events = {}, nativeEvents = {} } = field   const getEvents = events= > {  const newEvents = {}  Object.keys(events).forEach(key= > {  const event = events[key]  newEvents[key] = (. rest) = > {  const args = [ . rest, {  rowId,  row: this.editRowsData[rowId],  value: this.editRowsData[rowId][field.prop]  }  ]  returnevent(... args) }  })  return newEvents  }  // Event overwrite  const newEvents = getEvents(events)  const newNativeEvents = getEvents(nativeEvents)  return (  <Component  size="small"  on={newEvents}  nativeOn={newNativeEvents}  v-model={this.editRowsData[rowId][field.prop]}  {.{  attrs: field. props: field  }}  />  )  } Copy the code

conclusion

This table contains many features, article length is preferred, if you find it useful, you can visit github.com/snowzijun/v… View the complete code, the warehouse code and documentation will continue to improve, welcome star. Edge began to accumulate, pay attention to the public number, small make up to pull you into the front end of the communication group


I’m Zijun. Every Monday, be there or be square

Actual combat skills, Vue can also be written like this original 2700+ praise

Absolute dry goods ~! With these Vue tips, you can leave work early and date the goddess with 1200 likes

High energy ahead, this is the latest wave of Vue combat skills, once used, amazing praise 1000+

This is how I configured Vue to win 1000+ in the project

Learn to use Vue JSX, a car full of Laoganma will get you 700+

Tips for making Vue projects more silky received 300+ upvotes

See earn! Rereading the vue2.0 style guide, I compiled these key rules and received 150+ likes

conclusion

Don’t blow out your inspiration and your imagination; Don’t be a slave to your model. — Vincent Van Gogh

This article is formatted using MDNICE