preface

Cause:

When using the Element-UI table component, because the table column is more troublesome to write one by one, so we want to define all table headers as an array, through traversal multiple ways to achieve. This solves the problem of writing many el-table-columns by hand.

Obstacle:

Similar to the following custom table column style, it is implemented by slot-scope to override the internal slot style of el-table-column. So how do we do that when we iterate through the header array? Reference:

React development uses Ant Design a lot. The table component accepts the render attribute. When using the Table component, define columns and data. The overall look is simple to render custom components.Check out AntDesign

Demo: codepen Indicates the demo address

const columns = [
  {
    title: 'Name',
    dataIndex: 'name',
    render: (text, row, index) => {
      if (index < 4) {
        return <a>{text}</a>;
      }
      return {
        children: <a>{text}</a>,
        props: {
          colSpan: 5,
        },
      };
    },
  }]
 const const data = [
  {
    key: '1',
    name: 'John Brown',
    age: 32,
    tel: '0571-22098909',
    phone: 18889898989,
    address: 'New York No. 1 Lake Park',
  }]
ReactDOM.render(<Table columns={columns} dataSource={data} bordered />, mountNode);
Copy the code

Implement the Render property in Vue

Next we’ll implement the table style shown below, but this time we’ll use render to pass parameters

Train of thought

  1. The parent component passes the list that needs to be rendered to the child component via props
  2. The child component uses slot and populates the values passed in prop render data in the default render el-table-column mode
  3. The child component passes the value back to the parent component via slot. The parent component receives the value of the child component via slot-scope and determines whether the item has the Render attribute. If so, add the HTML returned by the Render attribute to the component tag to override the default value in the slot.

Child components define default values

With that in mind, implement the subcomponents. We need to remember that each el-table-column is just a column of headers and data, whereas :data=”tableList” is a row of data. So el-table-column is divided by column, and data is divided by row

  1. Accept the list of headers, the list of data, through props
  2. Iterate over the table header data and make el-table-column the default data, wrapped in slot
  3. Pass the current item’s data to the parent component through slot
<template> <el-table :data="tableList" style="width:500px"> <template v-for="item in propList"> <slot :content="item"> <el-table-column :key="item.id" :prop="item.prop" :label="item.label"></el-table-column> </slot> </template> </el-table>  </template> <script> export default { props:{ propList:{ type:Array, default:()=>[] }, tableList:{ type:Array, default:()=>[] }, } } </script>Copy the code

Parent component definition

The parent component receives data from the child component via slot-scope, and then determines whether the render attribute is available to override the default slot with a custom style

  1. Looking first at the header data passed to the child component, you can see that the second and third column tables have a render attribute, which is a function and returns an HTML string.
  2. A tableList is a common data, that is, the key of the data to render the corresponding data
  3. In this example, after the parent component passes {label,prop, ID,render} to the child component via props, the child component passes the value back to the parent component via slot.
    • At this point, some people might wonder why we’re passing data around like this, because we’ve defined the default style in the child, and the parent component needs to determine if the value needs a custom style to override the style in the child.
    • These custom styles are the HTML strings returned in the render function at the beginning
    • React returns JSX directly, whereas Vue returns HTML strings. React uses JSX to render the template. This is eventually compiled into react. createElement via Babel, whereas Vue renders the template from template, which is then parsed through V-HTML by defining the template string
  4. Why there are two slot-scopes here? The first one is for a slot-item, and the value is passed inside the component by slot-scope. The second is the EL-table-item UI component that also passes data from within the slot-Scope.
  5. The first slot-scope gets the render function defined in propList, and the second slot-scope gets the data passed inside the table component and passes it to the render function to generate the custom template
  6. Finally, v-HTML is used to parse the generated string template
<slot-item :propList="propList" :tableList="tableList"> <template slot-scope="{content}" v-if="content.render"> <el-table-column :label="content.label"> <template slot-scope="{$index,row}"> <div v-html="content.render(row)"></div> </template> </el-table-column> </template> </slot-item> export default { components:{ SlotItem }, Data () {return {propList:[{label:' name', prop:'name',id:1}, {label: 'images', prop:' PIC, id: 2, render: (= > {return} {PIC) ` < img style = "width: 30 px; height:30px" src='${pic}' />` }}, {label: 'operation', prop: 'operate', id: 3, render () = > {text} {return ` < div style = "color: # 999" > ${text} < / div > `}},]. tableList:[ {name: 'in chapter three, the PIC:' https://zh-static-files.oss-cn-hangzhou.aliyuncs.com//karazhan/content/poster/2019/11/16e30c192f6.png ', t Ext: 'new'}, {name: 'he', PIC: 'https://zh-static-files.oss-cn-hangzhou.aliyuncs.com//karazhan/content/poster/2019/11/16e30c2797e.png', t Ext: 'delete'}, {name: 'net dance, PIC:' https://zh-static-files.oss-cn-hangzhou.aliyuncs.com//karazhan/content/poster/2019/11/16e30c33144.png ', t Ext :' jump '},]}}} </script>Copy the code

The event agent

Since the form of the v-HTML parsed string is not compiled by VUE, you need to delegate the bound events to the parent level to perform different logic based on the event source

<div v-html="content.render($index,row,total)" @click="onProxyClick($index,row,'tablePoster',$event)"></div> methods:{ OnProxyClick ($index,row,ref,event) {Copy the code

Custom single-column table header

Sometimes we just want to change the display of the header of a table column. If we look at the official documentation and find the table-column Attributes column, we find the render-header attribute.

<el-table-column prop="teach" label=" teacher ":render-header="renderHeader" > // elder-ui provides custom table headers, RenderHeader (h,{column,$index}) {return H (' div '{}, [' custom title, h (' I', {class: 'el - icon - arrow - down, style: {fontSize:' 12 px, the transform: 'scale (0.8)'}})])},Copy the code

At the end

With the Render property, you can use a simple property UI component template like ant-Design!