【Vue】彻底理解Vue中render函数与template的区别

一、render函数与template对比

VUE一般使用template来创建HTML,然后在有的时候,我们需要使用javascript来创建html,这时候我们需要使用render函数。

 

以下我们来做一个需求跟根据level等级来编写对应等级的标题

template解析

<body>
   <divid="app">
       <h-titlelevel=1>
           <p>li</p>
       </h-title>
       <h-titlelevel=2>
           <p>li</p>
       </h-title>
   </div>
</body>

</html>
<scriptsrc="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
//在这里玩们需要通过v-if来进行判断
   Vue.component("h-title", {
       template: `<div>
           <h1 v-if="level==1"><slot></slot></h1>
           <h2 v-else-if="level==2"><slot></slot></h2>
       </div>`,
       props: {
           level: {
               type: Number,
               required: true
          }
      }
  })

   letvm=newVue({
       el: "#app"
  })
</script>

 

render解析


<body>
   <divid="app">
       <h-titlelevel=1>
           <p>Alley</p>
       </h-title>
       <h-titlelevel=2>
           <p>Alley</p>
       </h-title>
   </div>
</body>

</html>
<scriptsrc="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
   Vue.component("h-title", {
       render:function(createElement){
           returncreateElement(
               "h"+this.level,
               this.$slots.default
          )
      },
       props: {
           level: {
               type: Number,
               required: true
          }
      }
  })

   letvm=newVue({
       el: "#app"
  })
</script>

二者对比我们不难看出render函数创建组件的方式更加的灵活,同时也能让我们最大的发挥出JavaScript的编程能力

 

二、render函数详解

Vue中的Render函数中有一个参数,这个参数是一个函数通常我们叫做h。其实这个h叫做createElement。Render函数将createElement的返回值放到了HTML中

createElement这个函数中有3个参数

  • 第一个参数(必要参数):主要用于提供DOM的html内容,类型可以是字符串、对象或函数

  • 第二个参数(类型是对象,可选):用于设置这个DOM的一些样式、属性、传的组件的参数、绑定事件之类

  • 第三个参数(类型是数组,数组元素类型是VNode,可选):主要是指该结点下还有其他结点,用于设置分发的内容,包括新增的其他组件。注意,组件树中的所有VNode必须是唯一的

// @return {VNode}
createElement(
 // {String | Object | Function}
 // 一个HTML标签字符串,组件选项对象,或者一个返回值类型为String/Object的函数。该参数是必须的
 'div',

 // {Object}
 // 一个包含模板相关属性的数据对象,这样我们可以在template中使用这些属性,该参数是可选的。
{
     attrs: {
        name: headingId,
        href: '#'+headingId
    },
     style: {
        color: 'red',
        fontSize: '20px'
    },
     'class': {
        foo: true,
        bar: false
      },
      // DOM属性
      domProps: {
         innerHTML: 'baz'
      },
      // 组件props
       props: {
          myProp: 'bar'
      },
       // 事件监听基于 'on'
       // 所以不再支持如 'v-on:keyup.enter' 修饰语
       // 需要手动匹配 KeyCode  
       on: {
           click: function(event) {
                event.preventDefault();
                console.log(111);
          }
        }
  }

 // {String | Array}
 // 子节点(VNodes)由 createElement() 构建而成。可选参数
 // 或简单的使用字符串来生成的 "文本节点"。
[
   'xxxx',
   createElement('h1', '一则头条'),
   createElement(MyComponent, {
     props: {
       someProp: 'xxx'
    }
  }),
   this.$slots.default
]
)

 

三、什么时候用render函数?

假设我们要封装一套按钮组件,按钮有四个样式(success、error、warning、default)。首先,你可能会想到如下实现

<template>
<divclass="btn btn-success"v-if="type === 'success'">{{ text }}</div>
<divclass="btn btn-danger"v-else-if="type === 'danger'">{{ text }}</div>
<divclass="btn btn-warning"v-else-if="type === 'warning'">{{ text }}</div>
</template>

虽然我们这样实现没有问题,但是如果现在有十几个样式的情况下我们就需要写N多个判断,如果遇到了这种情况我们就可以选择使用render函数。

其实简单的来说就是template适合简单的组件封装,然后render函数适合复杂的组件封装

<script>
Vue.component("A-button", {
       props: {
           type: {
               type: String,
               default: 'default'
          },
           text: {
               type: String,
               default: '按钮'
          }
      },
       computed: {
           tag() {
               switch(this.type) {
                   case'success':
                       return1;
                   case'danger':
                       return2;
                   case'warning':
                       return3;
                   default:
                       return1;
              }
          }
      },
       render(h) {
           returnh('div', {
               class: {
                   btn: true,
                   'btn-success': this.type==='success',
                   'btn-danger': this.type==='danger',
                   'btn-warning': this.type==='warning'
              },
               domProps: {
                   //innerText: this.text,
              },
               on: {
                   click: this.handleClick
              }
          },
           this.$slots.default
          );
      },
       methods: {
           handleClick() {
               console.log('-----------------------');
               console.log('li');
          }
      }
  })

   letvm=newVue({
       el: "#app"
  })
</script>

 

四、template与render函数对比

相同之处:

render 函数template 一样都是创建 html 模板

不同之处:

  • Template适合逻辑简单,render适合复杂逻辑。

  • 使用者template理解起来相对容易,但灵活性不足;自定义render函数灵活性高,但对使用者要求较高。

  • render的性能较高,template性能较低。这一点我们可以看一下,下图中vue组件渲染的流程图可知。

  • 基于上一点,我们通过vue组件渲染流程图知道,使用render函数渲染没有编译过程,相当于使用者直接将代码给程序。所以,使用它对使用者要求高,且易出现错误

  • Render 函数的优先级要比template的级别要高,但是要注意的是Mustache(双花括号)语法就不能再次使用

上一篇:React.createElement源码理解-1


下一篇:假如React没了JSX