1. Dynamic forms

Sometimes we need to create and change forms dynamically in our admin system. However, when we write a form with template, this requirement is difficult to fulfill without being able to configure the form with JSON, even if it is packaged as a component, and we have to use countless V-Ifs to determine what component we should render.

<el-input v-if="item.type === 'input'" /> <el-select v-else-if="item.type === 'select'" >... </el-select>Copy the code

Code like this, of course, does the job, but it always feels like a chore, and if there’s a freak requirement, it might not be easy to write. This is where JSX can help.

  init() {
    let arr = []
    this.items.forEach((element) = > {
      arr.push(this.type[element.type]())
    })
  },
  ......
  render() {
    return <div>
    {this.init()}   
    </div>
  }
Copy the code

In vue-CLI 3.0 and later, you can use JSX directly.

It is also very easy to write. We create a vue file and write a script tag instead of a template tag

<script>
export default {
  name: 'HelloWorld'.props: {
    msg: String
  },
  data() {
    return {
      message: 'HelloWorld'}},render() {
    return <div>{this.message},{this.msg}</div>
  }
}
</script>
Copy the code

That’s all there is to this file, and then we just import it as a component into other files as normal. Use is also how normal components are used. Once we have introduced elementUI normally, we can use the components in the UI to build our interface, as shown below

// render.vue
<script>
export default {
  data() {
    return {
      msg: 'Hello World'.initForm: {
        input: this.createInput,
        select: this.createSelect,
      },
      form:}}, {},props: {
    items: {
      type: Array.default: () = >[],}},methods: {
    onClick() {
      console.log(this.form)
    },
    createInput(options) {
      return <elInput v-model_trim={this.form[options.name]}></elInput>
    },
    createSelect(options) {
      const option = options.option.map((item) = > (
        <el-option label={item.label} value={item.value}></el-option>
      ))
      return <el-select v-model={this.form[options.name]}>{option}</el-select>
    },
    init() {
      let arr = []
      this.items.forEach((element) = > {
        arr.push(this.initForm[element.type](element.options))
      })
      return arr
    },
    returnForm() {
      return this.form
    },
  },
  render() {
    return (
      <div>
        {this.init()}
        <el-button onClick={this.onClick}>submit</el-button>
      </div>
    )
  },
}
</script>

// test.vue
<template>
  <div>
    <render :items="items"></render>
  </div>
</template>

<script>
import render from '.. /components/render.vue'
export default {
  components: {
    render,
  },
  data() {
    return {
      items: [{type: 'input'.options: {
            name: 'name',},},],}},}</script>
Copy the code

As you can see, we successfully created an input box from an array and bound it to the V-Model. With built-in methods, we can also pass data to other components, getting rid of the heavy template, replacing v-if with a judgment, and v-for with a for. You gain a more flexible way to create pages. However, due to js limitations, to use v-model.trim, we have to change it to V-mode_trim.

In practice, we will definitely use slots, and JSX slots are very simple

// test.vue
<render :items="items">
      <div>test</div>
</render>
Copy the code
// render.vue
return (
<div>
  {this.init()}
  {this.$slots.default}
</div>
)
Copy the code

Just like this, we render the desired component from the information in this.$slot (i.e. VNode). We can even loop $slot with forin so that we don’t have to write it out in the child component even if the parent component uses more named slots. Similarly, we can see that information about the VUE components can be found in this, which we can use if needed when working with JSX. Examples of listeners are this.$attr, this.$Listeners, and so on.

2. Dynamic tables

Also, we can wrap the table with JSX just like we can wrap the form. It’s worth noting that we have a need for custom cells for the table, but with This and Render, it’s not difficult to do that. Custom cells can be treated as a slot and rendered directly from slot. We can also render directly from JSON (not strictly speaking), since we can use JSX directly in the array, we just need to pass out the data needed for rendering.

// table.vue
initTable() {
      const columns = this.tableHeaders.map(i= > {
        if (i.slot) {
          return this.$slots[i.slot][0]}else if (i.render) {
          const custom = scope= > i.render(scope, scope.row)
          return  <el-table-column label={i.label}>{custom}</el-table-column>
        } else {
          return  <el-table-column prop={i.prop} label={i.label}></el-table-column>}})returnThe columns} · · · · · ·render() {
    const prop = {
      attrs: this.$attrs,
      on: this.$listeners
    }
    return (
      <el-table data={this.tableData} {. prop} style='width: 100%'>
        {this.initTable()}
      </el-table>)},Copy the code
// test.vue
    <my-table :tableData="tableData" :tableHeaders="tableHeaders">
      <template v-slot:date>
        <el-table-column
          label="Date"
          width="180"
          >
          <template slot-scope="scope">
            <i class="el-icon-time"></i>
            <span style="margin-left: 10px">{{ scope.row.date }}</span>
          </template>
        </el-table-column>
      </template>
    </my-table>
<script>
 tableHeaders = [
        {label: 'date'.prop: 'date'.slot: 'date'},
        {label: 'name'.prop: 'name'},
        {label: 'address'.prop: 'address'.render: (index, row) = > {
            return  <span style="color: red">{row.address}</span>}},]</script>
Copy the code

With JSX, we can easily accomplish dynamic requirements.