美文网首页
Vue进阶——render函数

Vue进阶——render函数

作者: 追风少年_hxb | 来源:发表于2021-10-21 11:18 被阅读0次

    一、render函数语法

    了解render函数之前我们要先了解一个概念-虚拟DOM

    DOM是文档对象模型(Document Object Model)的简写,在浏览器中通过js来操作DOM的操作性能很差,于是虚拟Dom应运而生。虚拟Dom就是在js中模拟DOM对象树来优化DOM操作的一种技术或思路。React 和 Vue2都使用了虚拟DOM技术,虚拟DOM并不是真正意义上的DOM,它作为一个轻量级的JavaScript对象,在 状态发生变化时,会进行Diff运算,来更新发生变化的DOM,对于未发生变化的DOM节点,不予操作,由于不是全部重绘,大大提高更新渲染性能。当使用render函数描述虚拟DOM时,vue提供一个函数,这个函数是就构建虚拟DOM所需要的工具。官网上给他起了个名字叫 createElement。还有约定的简写叫 h, vm中有一个方 法 _c, 也是这个函数的别名。在Vue2中,虚拟DOM就是通过一种VNode类表达,每个DOM元素或组件都对应一个VNode对象。

    1286849-20190918164323177-2021260734.png
    render函数的参数(createElement)

    1、createElement 函数的返回值是 VNode(即:虚拟节点)。
    2、createElement 函数的参数(三个)
    2.1、一个 HTML 标签字符串,组件选项对象,或者解析上述任何一种的一个 async 异步函数。类型:{String | Object | Function}。必需。
    2.2、一个包含模板相关属性的数据对象你可以在 template 中使用这些特性。类型:{Object}。可选。
    2.3、子虚拟节点 (VNodes),由 createElement() 构建而成,也可以使用字符串来生成“文本虚拟节点”。类型:{String | Array}。可选。
    3、结合代码

     /**
      * render: 渲染函数
      * 参数: createElement
      * 参数类型: Function
     */
     render: function (createElement) {
       let _this = this['$options'].parent  // 我这个是在 .vue 文件的 components 中写的,这样写才能访问this
       let _header = _this.$slots.header    // $slots: vue中所有分发插槽,不具名的都在default里
     
       /**
        * createElement 本身也是一个函数,它有三个参数
        * 返回值: VNode,即虚拟节点
        * 1. 一个 HTML 标签字符串,组件选项对象,或者解析上述任何一种的一个 async 异步函数。必需参数。{String | Object | Function} - 就是你要渲染的最外层标签
        * 2. 一个包含模板相关属性的数据对象你可以在 template 中使用这些特性。可选参数。{Object} - 1中的标签的属性
        * 3. 子虚拟节点 (VNodes),由 `createElement()` 构建而成,也可以使用字符串来生成“文本虚拟节点”。可选参数。{String | Array} - 1的子节点,可以用 createElement() 创建,文本节点直接写就可以
        */
       return createElement(       
         // 1. 要渲染的标签名称:第一个参数【必需】      
         'div',   
         // 2. 1中渲染的标签的属性,详情查看文档:第二个参数【可选】
         {
           style: {
             color: '#333',
             border: '1px solid #ccc'
           }
         },
         // 3. 1中渲染的标签的子元素数组:第三个参数【可选】
         [
           'text',   // 文本节点直接写就可以
           _this.$slots.default,  // 所有不具名插槽,是个数组
           createElement('div', _header)   // createElement()创建的VNodes
         ]
       )
     }
    

    第二个参数的具体属性如下:

    {
      // 与 `v-bind:class` 的 API 相同,
      // 接受一个字符串、对象或字符串和对象组成的数组
      'class': {
        foo: true,
        bar: false
      },
      // 与 `v-bind:style` 的 API 相同,
      // 接受一个字符串、对象,或对象组成的数组
      style: {
        color: 'red',
        fontSize: '14px'
      },
      // 普通的 HTML attribute
      attrs: {
        id: 'foo'
      },
      // 组件 prop
      props: {
        myProp: 'bar'
      },
      // DOM property
      domProps: {
        innerHTML: 'baz'
      },
      // 事件监听器在 `on` 内,
      // 但不再支持如 `v-on:keyup.enter` 这样的修饰器。
      // 需要在处理函数中手动检查 keyCode。
      on: {
        click: this.clickHandler
      },
      // 仅用于组件,用于监听原生事件,而不是组件内部使用
      // `vm.$emit` 触发的事件。
      nativeOn: {
        click: this.nativeClickHandler
      },
      // 自定义指令。注意,你无法对 `binding` 中的 `oldValue`
      // 赋值,因为 Vue 已经自动为你进行了同步。
      directives: [
        {
          name: 'my-custom-directive',
          value: '2',
          expression: '1 + 1',
          arg: 'foo',
          modifiers: {
            bar: true
          }
        }
      ],
      // 作用域插槽的格式为
      // { name: props => VNode | Array<VNode> }
      scopedSlots: {
        default: props => createElement('span', props.text)
      },
      // 如果组件是其它组件的子组件,需为插槽指定名称
      slot: 'name-of-slot',
      // 其它特殊顶层 property
      key: 'myKey',
      ref: 'myRef',
      // 如果你在渲染函数中给多个元素都应用了相同的 ref 名,
      // 那么 `$refs.myRef` 会变成一个数组。
      refInFor: true
    }
    

    二、render函数的简单应用

    <!doctype html>
    <html lang="en">
     
    <head>
        <meta charset="UTF-8" />
        <title>Document</title>
    </head>
     
    <body>
        <div id="app">
            <child :level=1>hello Vue</child>
            <child :level=6>
                <span slot="footer">span</span>
                <p slot="header">header slot<span>span</span></p>
            </child>
        </div>
        <script src="node_modules/vue/dist/vue.js"></script>//使用时改为自己的vue路径
        <script>
        Vue.component('child', {
            render: function(createElement) {
                return createElement('h'+ this.level, {
                    'class': {
                        foo: true,
                        bar: true
                    },
                    style: {
                        color: "red"
                    },
                    attrs: {
                        id: 'foo',
                        'data-id': 'bar'
                    },
                    domProps: {
                        //
                    },
                    on: {
                        click: this.clickit
                    },
                },
                [this.$slots.default]
               )
            },
            template: '<div v-if="level===1"><slot></slot></div>',
            props: {
                level: {
                    type: Number,
                    required: true
                }
            },
            methods: {
                clickit: function() {
                    console.log('click')
                }
            }
        })
        new Vue({
            el:"#app"
        })
        </script>
    </body>
     
    </html>
    

    相关文章

      网友评论

          本文标题:Vue进阶——render函数

          本文链接:https://www.haomeiwen.com/subject/wmjboltx.html