# Vue 中 render 的使用价值

# 场景

假设说是低代码平台配置好的表单渲染,亦或者说自己封装的一个表单组件,通过传配置项来渲染,一般我们会怎么做呢?

# 常规做法

<template>
  <div class="wrapper">
    <div  
      v-for="item in item"
      :key="item.id">
      <template v-if="item.type === 'input'">
        <input></input>
      </template>
      <template v-else-if="item.type === 'select'">
        <select></select>
      </template>
    </div>
  </div>
</template>

<script>
  import input from '@/component/input'
  import select from '@/component/select'
  export default {
    data(){
      return {
        item:[
          {
            id:'1'
            type:'input'
          },
          {
            id:'2'
            type:'select'
          }
        ]
      }
    },
    components:{
      input,
      select
    }
  }
</script>

# 说明

从以上代码可以看出,如果说,我们有 30 个 type ,那我们就必须用 import 导入 30 个组件,在 compoents 里面注册 30 个组件,在模板里面写 30 个 template + v-if ,越多代码只会越来越冗余,但是我们用 render 的方式来渲染呢?

所以从中看出,常规做法的可读性极强,但是代码太过冗余,重复代码太多

# render 使用

<template>
  <div class="wrapper">
    <div  
      v-for="item in item"
      :key="item.id">
      <business-component :item="item"/>
    </div>
  </div>
</template>

<script>
  import '@/utils/renderHandle.js'
  export default {
    data(){
      return {
        item:[
          {
            id:'1'
            type:'input'
          },
          {
            id:'2'
            type:'select'
          }
        ]
      }
    }
  }
</script>
Vue.component('business-component',{
  render(h,context){
    const item = context.props.item
    if(item && item.type){
      try {
        const component = require(`@/components/${type}.vue`)
        if(component){
          return h(component,context)
        }
      } catch (error) {
        console.log('error----',error);
      }
    }
    return h('div')
  }
})

从这两部分代码可以看出,我无论有多少个组件,都不用像常规做法那样疯狂注册,疯狂导入,所以显然这里用 render 的方法来渲染是很完美的,不过其实这并不完善,因为 vue.componet 方法的第二个参数可并不仅仅只有 render 方法,它还可以用很多其他属性,假设说我们需要在使用的时候去添加一下其他属性呢?总不可能直接在上面的这个 business-component 的注册函数里面加吧,它只是个中介而已,负责转发,所以我们需要一个玄妙的注册函数来反传回去给我们去加东西

Vue.component('business-component',{
  render(h,context){
    const compoentKey = context.props.key
    if(compoentKey){
      return h(compoentKey,context)
    }
    return h('div')
  }
})
export const registerFn = (key,fn) => {
  Vue.component(key,{
    render(h,context){
      const item = context.props.item
      const obj = fn(context)
      if(item && item.type){
        try {
          const component = require(`@/components/${type}.vue`)
          if(component){
            return h(component,obj)
          }
        } catch (error) {
          console.log('error----',error);
        }
      }
      return h('div')
    }
  })
}
<template>
  <div class="wrapper">
    <div  
      v-for="item in item"
      :key="item.id">
      <business-component 
        :item="item"
        :key="key"/>
    </div>
  </div>
</template>

<script>
  import { registerFn } '@/utils/renderHandle.js'
  export default {
    data(){
      return {
        item:[
          {
            id:'1'
            type:'input'
          },
          {
            id:'2'
            type:'select'
          }
        ],
        // 唯一的key
        key:999
      }
    },
    created(){
      this.register
    },
    methods:{
      register(){
        registerFn(this.key,(context) => {
          const {
            item
          } = context.props
          return {
            item,
            on: {
              test1(){
                console.log('我要监听了');
              }
            },
            off: {
              test2(){
                console.log('我不监听了');
              }
            }
          }
        })
      }
    }
  }
</script>

# 结语

是不是很简单呢,其实 render 也不是不能在 vue 中用的,有些场景它确实很好用

请我喝[茶]~( ̄▽ ̄)~*

呆头鸭 微信支付

微信支付

呆头鸭 支付宝

支付宝