• vue-render函数


    今天我们来看一下,vue的render函数。

    很多朋友对于长篇大论看不下去,有的呢是有接触过这些,所以我们今天吧总结写在前边。需要的朋友可以往下看: 
    总结: 
    1. render方法的实质就是生成template模板; 
    2. 通过调用一个方法来生成,而这个方法是通过render方法的参数传递给它的; 
    3. 这个方法有三个参数,分别提供标签名,标签相关属性,标签内部的html内容 
    4. 通过这三个参数,可以生成一个完整的木模板

    备注:

    1. render方法可以使用JSX语法,但需要Babel plugin插件;
    2. render方法里的第三个参数可以使用函数来生成多个组件(特别是如果他们相同的话),只要生成结果是一个数组,且数组元素都是VNode即可;

    注意: 
    render函数室友限制的,Vue.js 2.X支持,但是1.X无法使用。

    说明: 
    我们接着来,我们今天先来粗略的了解下render函数,后面我会用大量的代码进行说明,便于大家先简单的了解,后边我们在进行深入了解。

    基础

    什么是render函数呢?Vue官方给我们已经说明。 
    VUE推荐在绝大多数情况下使用template来创建我们的HTML。然而在一些场景中,我们真的需要JavaScript的完全编程的能力,这就是render函数,它比template更接近编译器。

    1.  
      <h1>
    2.  
      <a name="hello-world" href="#hello-world">
    3.  
      Hello world!
    4.  
      </a>
    5.  
      </h1>

    在HTML层,我们决定这样定义组件接口:

    <anchored-heading :level="1">Hello world!</anchored-heading>

    当我们开始写一个通过levelprop 动态生成heading 标签的组件,你可能很快想到这样实现:

    1.  
      <script type="text/x-template" id="anchored-heading-template">
    2.  
      <h1 v-if="level === 1">
    3.  
      <slot></slot>
    4.  
      </h1>
    5.  
      <h2 v-else-if="level === 2">
    6.  
      <slot></slot>
    7.  
      </h2>
    8.  
      <h3 v-else-if="level === 3">
    9.  
      <slot></slot>
    10.  
      </h3>
    11.  
      <h4 v-else-if="level === 4">
    12.  
      <slot></slot>
    13.  
      </h4>
    14.  
      <h5 v-else-if="level === 5">
    15.  
      <slot></slot>
    16.  
      </h5>
    17.  
      <h6 v-else-if="level === 6">
    18.  
      <slot></slot>
    19.  
      </h6>
    20.  
      </script>
    1.  
      Vue.component('anchored-heading', {
    2.  
      template: '#anchored-heading-template',
    3.  
      props: {
    4.  
      level: {
    5.  
      type: Number,
    6.  
      required: true
    7.  
      }
    8.  
      }
    9.  
      })
    •  

    在这种场景中使用 template 并不是最好的选择:首先代码冗长,为了在不同级别的标题中插入锚点元素,我们需要重复地使用<slot></slot>

    虽然模板在大多数组件中都非常好用,但是在这里它就不是很简洁的了。那么,我们来尝试使用render函数重写上面的例子:

    1.  
      Vue.component('anchored-heading', {
    2.  
      render: function (createElement) {
    3.  
      return createElement(
    4.  
      'h' + this.level, // tag name 标签名称
    5.  
      this.$slots.default // 子组件中的阵列
    6.  
      )
    7.  
      },
    8.  
      props: {
    9.  
      level: {
    10.  
      type: Number,
    11.  
      required: true
    12.  
      }
    13.  
      }
    14.  
      })
    •  

    简单清晰很多!简单来说,这样代码精简很多,但是需要非常熟悉 Vue 的实例属性。在这个例子中,你需要知道当你不使用slot 属性向组件中传递内容时,比如 anchored-heading 中的 Hello world!, 这些子元素被存储在组件实例中的 $slots.default中。如果你还不了解, 在深入 render 函数之前推荐阅读实例属性API。

    我们来一个生成模板对比,便于学习 
    非使用render方法的情况下

    1.  
      <div id="app">
    2.  
      <child :level="1">Hello world!</child>
    3.  
      </div>
    4.  
      <script type="text/x-template" id="template">
    5.  
      <div>
    6.  
      <h1 v-if="level === 1">
    7.  
      <slot></slot>
    8.  
      </h1>
    9.  
       
    10.  
      <h2 v-if="level === 2">
    11.  
      <slot></slot>
    12.  
      </h2>
    13.  
       
    14.  
      <h3 v-if="level === 3">
    15.  
      <slot></slot>
    16.  
      </h3>
    17.  
       
    18.  
      <h4 v-if="level === 4">
    19.  
      <slot></slot>
    20.  
      </h4>
    21.  
       
    22.  
      <h5 v-if="level === 5">
    23.  
      <slot></slot>
    24.  
      </h5>
    25.  
       
    26.  
      <h6 v-if="level === 6">
    27.  
      <slot></slot>
    28.  
      </h6>
    29.  
      </div>
    30.  
      </script>
    31.  
       
    32.  
       
    33.  
       
    34.  
      <script type="text/javascript">
    35.  
       
    36.  
      Vue.component('child', {
    37.  
      template: '#template',
    38.  
      props: {
    39.  
      level: {
    40.  
      type: Number,
    41.  
      required: true
    42.  
      }
    43.  
      }
    44.  
      })
    45.  
       
    46.  
      new Vue({
    47.  
      el: "#app"
    48.  
      })
    49.  
       
    50.  
      </script>
    •  

    代码说明: 
    1. 最下面的new Vue方法很明显,是new了一个Vue的实例,挂载点#app这个dom; 
    2. Vue.component这部分代码,第一个参数表示注册了一个Vue的组件,标签名是child(即 <child> 标签会被替换); 
    3. 第二个参数中,template属性表示取找id=“template”的标签(另注,这个标签是<script>,或者是<div>,或者是template,或者是其他,没有影响),然后将这个标签作为组件的模板; 
    4. props表示传递给这个组件的变量,通过标签中的v-bind:level这种形式传递变量level的值等于1。在这里的写法是限制变量类型为number,并且强制需要; 
    5. slot表示内容分发,具体来说,就是把组件替换的源html标签里的内容(如 <child> 标签里面的内容,不包含 <child> 标签本身,这里是Hello world!),发在 <slot> 标签所在的位置(即放在<h1>-<h2> 这样的标签内); 
    6. 如果还不理解,可以运行该段代码查看结果,或者去看vue的官方文档说明; 
    7. 总的来说,顺序如下:注册一个组件,这个组件有模板,这个模板里有一个变量,变量的值通过父组件来传递,然后根据变量的值,通过v-if命令显示对应的html标签内容,然后在父组件里使用这个组件,让子组件显示需要显示的内容。

    这样的代码有一个缺陷,就是需要大量重复的代码。如<h1>~<h6>共六种情况。如果这样的模板比较复杂,比如<hx>标签里还有很多其他内容,显然会让人十分困扰,既不美观又不好用。 
    使用render方法的情况

    1.  
      <div id="app">
    2.  
      <child v-bind:level="2">Hello world!</child>
    3.  
      </div>
    4.  
       
    5.  
      <script type="text/javascript">
    6.  
       
    7.  
      Vue.component('child', {
    8.  
      render: function (createElement) {
    9.  
      return createElement(
    10.  
      'h' + this.level, // tag name 标签名称
    11.  
      this.$slots.default // 子组件中的阵列
    12.  
      )
    13.  
      },
    14.  
      props: {
    15.  
      level: {
    16.  
      type: Number,
    17.  
      required: true
    18.  
      }
    19.  
      }
    20.  
      })
    21.  
       
    22.  
      new Vue({
    23.  
      el: "#app"
    24.  
      })
    25.  
       
    26.  
      </script>
    •  

    代码说明:

    1. 这里的代码和上面区别之处有两点: 
      其一,没有显式的模板内容,而是通过render方法生成; 
      其二,使用了createElement方法。
    2. 关于createElement方法,他是通过render函数的参数传递进来的,这个方法有三个参数: 
      第一个参数主要用于提供dom的html内容,类型可以是字符串、对象或函数。比如”div”就是创建一个 <div>标签 
      第二个参数(类型是对象)主要用于设置这个dom的一些样式、属性、传的组件的参数、绑定事件之类,具体可以参考 官方文档 里这一小节的说明 
      第三个参数(类型是数组,数组元素类型是VNode)主要用于说是该结点下有其他结点的话,就放在这里。

    比如说,有需要分发的标签 <slot>,则通过 this.$slots.default 来获得,或许还有其他组件之类,可能需要被使用的,应该也是放在这里。 
    个人初步理解是,在原本被替换的地方,例如例上面代码中的 <child> 标签,在其下的每个次一级标签为一个元素,放在 this.$slots.default这个数组中,例如上面的话,这个数组只有一个元素,但是以下代码: 

    <child v-bind:level="2"><div>Hello</div><div> world!</div></child> 

    这个数组中则有两个元素,分别是 <div>Hello</div> 和 <div> world!</div>例如 this.$slots.default[0] 则表示第一个标签。

    另外,假如这2个元素中间有空格、换行符之类,那么数组中则有三个元素,那个空格、换行符则为第二个元素。这个属性有点类似dom的 childNodes属性,不是单纯以标签才算作子节点的。(但注意,不是完全相同)

    有时候,我们可能想在里面添加其他的组件,例如将abc组件注册在里面。那么,我们首先要注册这个abc组件,然后将abc组件在数组里通过createElement来创建标签,只有通过这样的方式创建的abc标签,才能被abc组件使用。单纯输入字符串"<abc></abc>" 这样是不可以的。

    如以下代码也是可行的(在通过render方法生成的模板中添加别的组件):

    1.  
      <div id="app">
    2.  
      <child v-bind:level="2">
    3.  
      <div>Hello</div>
    4.  
      <div> world!</div>
    5.  
      </child>
    6.  
      </div>
    7.  
       
    8.  
      <script>
    9.  
       
    10.  
      Vue.component('abc', {
    11.  
      template: "<div>abc</div>"
    12.  
      })
    13.  
       
    14.  
      Vue.component('child', {
    15.  
      render: function (createElement) {
    16.  
      console.log(this.$slots)
    17.  
      return createElement(
    18.  
      'h' + this.level, // tag name 标签名称
    19.  
      [this.$slots.default[0], createElement("abc"), this.$slots.default[1]] // 子组件中的阵列
    20.  
      )
    21.  
      },
    22.  
      props: {
    23.  
      level: {
    24.  
      type: Number,
    25.  
      required: true
    26.  
      }
    27.  
      }
    28.  
      })
    29.  
       
    30.  
      new Vue({
    31.  
      el: "#app"
    32.  
      })
    33.  
       
    34.  
      </script>
    •  

    显示结果是:

    Hello

    abc

    world!

    最后,如果想将原有内容全部使用(而不是只取部分标签),那么直接使用 this.$slots.default 作为第三个参数即可,他本身就是一个数组。

    总而言之,createElement方法的作用就是动态的创建一个dom用于被render函数渲染,其中参数二和参数三可以选择性省略,参数二用于设置dom的样式、属性、事件等,参数三用于设置分发的内容,包括新增的其他组件。 
    粗略理解的话,可以理解为:createElement( 标签名, 标签属性, 标签里的内容)。

    这样的话,我们就有了一个组件的模板所需要的全部内容了。后边我们在深入的了解下render函数。

  • 相关阅读:
    回顾2018,展望2019
    NLog日志框架使用探究-1
    基于NetMQ的TLS框架NetMQ.Security的实现分析
    鸟哥的Linux私房菜笔记第五章,文件权限与目录配置(二)
    鸟哥的Linux私房菜笔记第五章,文件权限与目录配置(一)
    鸟哥的Linux私房菜笔记第四章
    ThinkPHP5.1 + tufanbarisyildirim 解析apk
    Java核心技术第八章——泛型程序设计(1)
    Java核心技术第五章——2.Object类
    Java核心技术第五章——1.类、超类、子类(2)
  • 原文地址:https://www.cnblogs.com/yf2196717/p/11583417.html
Copyright © 2020-2023  润新知