VUE学习总结之render渲染

最近要做一个组件,但是组件的template部分过于繁琐,因此考虑用render来自动绘制template。关于这一部分内容,官网的介绍不够清晰,其他的教程也大多是千篇一律的复制结果,因此分享下我的关于这一部分的心得。

1. 需求

我要做的是一个业务相关的组件,就是动态地创建表格(包括跟数据相关的一些样式),并往表格里面填入信息,以及对表格中数据的一些操作。由于数据不是固定的,因此只能用函数来解决。之前对Vue不熟悉,我是用元素js加上JQ实现的。现在学了render渲染,因此我用render重新做了一遍。

2. 基础知识

一般来说,我们在创建页面的时候,都倾向于使用模板来实现,这也是官方推荐的方式。但有时我们并不能在一开始就确定我们HTML的内容及样式,这时我们就可以使用渲染函数来解决问题。有时为了简化代码,我们也可以将模板里的内容用render来实现,例如官网里面关于标题的例子
在使用render函数时,我们需要删除.vue文件中的< template >部分,否则渲染函数的结果无法显示。

2.1 节点、树以及虚拟DOM

关于这一部分,大家可以直接参考官方的介绍

2.1.1 节点、树

关于DOM节点树这一部分,需要注意的是,在一段HTML代码中,DOM元素可以作为一个节点,一段文字也可以作为节点,一段注释也可以作为节点。 所以在createElement的子节点参数中,我们可以将一段文本作为子节点。

2.2.2 虚拟DOM

Vue 通过建立一个虚拟 DOM 来追踪自己要如何改变真实 DOM。请仔细看这行代码:

return createElement('h1', this.blogTitle)

对于createElement ,它更准确的名字可能是 createNodeDescription,因为它所包含的信息会告诉 Vue 页面上需要渲染什么样的节点,包括及其子节点的描述信息。 我们把这样的节点描述为“虚拟节点 (virtual node)”,也常简写它为“VNode”。“虚拟 DOM”是我们对由 Vue 组件树建立起来的整个 VNode 树的称呼。

2.2 createElement参数

官方给出了createElement函数的API,如下所示

// @returns {VNode}
createElement(
 // {String | Object | Function}
 // 一个 HTML 标签名、组件选项对象,或者
 // resolve 了上述任何一种的一个 async 函数。必填项。
 'div',

 // {Object}
 // 一个与模板中属性对应的数据对象。可选。
 {
   // (详情见下一节)
 },

 // {String | Array}
 // 子级虚拟节点 (VNodes),由 `createElement()` 构建而成,
 // 也可以使用字符串来生成“文本虚拟节点”。可选。
 [
   '先写一些文字',
   createElement('h1', '一则头条'),
   createElement(MyComponent, {
     props: {
       someProp: 'foobar'
     }
   })
 ]
)

根据API的内容,我们可以知道,createElement可以有三个函数,一个必选项和两个可选项。
第一个参数可以填HTML标签名,组件选项对象(详见 示例1),或者一个函数(函数还没用过,按下不表)。
第二个参数填一些数据对象,具体下面会说。
第三个参数填子虚拟节点,一般都是调用createElement()创建新的虚拟节点,也可以使用字符串来生成“文本虚拟节点”。

2.2.1 深入数据对象

这一部分的数据主要是createElement()中第二个参数的内容,在这里你可以以对象的方式,填充DOM元素的属性、事件、自定义指令等,详见官方API。对于属性这一块,DOM元素的属性可能有class、style、id等,但在createElement语法中,class和style有特殊的key(class和style,class需要引号)来表示,而id这类的属性用的是另一个key(attrs)。

{
  // 与 `v-bind:class` 的 API 相同,
  // 接受一个字符串、对象或字符串和对象组成的数组
  'class': {
    foo: true,
    bar: false
  },
  // 与 `v-bind:style` 的 API 相同,
  // 接受一个字符串、对象,或对象组成的数组
  style: {
    color: 'red',
    fontSize: '14px'
  },
  // 普通的 HTML 特性
  attrs: {
    id: 'foo'
  },
  // 组件 prop。当createElement的第一个参数是组件对象时,可以使用这个
  props: {
    myProp: 'bar'
  },
  // DOM 属性
  domProps: {
    innerHTML: 'baz'
  },
  // 事件监听器在 `on` 属性内,
  // 但不再支持如 `v-on:keyup.enter` 这样的修饰器。
  // 需要在处理函数中手动检查 keyCode。
  // 为DOM元素绑定节点。
  on: {
    click: this.clickHandler
  },
  
  // 仅用于组件,用于监听原生事件,而不是组件内部使用 `vm.$emit` 触发的事件。
  // nativeOn与on的区别在于,nativeOn监控的是原生事件(例如按键的click,hover等),而on监控的是自定义事件
  nativeOn: {
    click: this.nativeClickHandler
  },
  // 自定义指令。如实现v-show指令
  directives: [
    {
   	   name: 'show',
 	   value: this.isShow
	}
  ],
  
  // 以下暂时都没用过
  // 作用域插槽的格式为
  // { name: props => VNode | Array<VNode> }
  scopedSlots: {
    default: props => createElement('span', props.text)
  },
  // 如果组件是其它组件的子组件,需为插槽指定名称
  slot: 'name-of-slot',
  // 其它特殊顶层属性
  key: 'myKey',
  ref: 'myRef',
  // 如果你在渲染函数中给多个元素都应用了相同的 ref 名,
  // 那么 `$refs.myRef` 会变成一个数组。
  refInFor: true
}
2.2.2 示例1:render的简单示例
<script>
  import MyButton from "./MyButton";
  export default {
    name: "HtmlArg",
    render(createElement) {
      return createElement(
        'div',
        {
          // class的需要一个引号
          'class':{
            'div1':true
          },
          attrs:{
            id:'firstDiv',
          }
        },
        // 第三个参数为子节点数组
        [
          // 第一个子节点
          createElement('button',{
            'class':{
              'div2':true
            },
            attrs:{
              value: 'okay'
            },
          },
            ['yellow']
          ),
          // 第二个子节点
          createElement('button',{
            'class':{
              'div3':true
            },
            attrs:{
              value: 'cancel'
            }
          } ,
            ['red']),
          // 第一个参数除了标签名以外,还可以填组件名
          // 第三个子节点
          createElement(MyButton)
        ]
      );
    }
  }
</script>

<style scoped>
  .div1{
    background: #0059F3;
  }
  .div2{
    background: yellow;
  }
  .div3{
    background: red;
  }
</style>

上述代码中定义了一个div标签。在数据对象部分,通过class进行了样式设置,通过attrs设置了该元素的id。最后在第三个参数中定义了所有的子节点,以数组的形式创建了三个子节点,值得注意的是,这里的第三个子子节点调用了我编写了另一个组件,也算是达到了代码复用的目的。不过那个组件的代码很简单,主要是为了演示组件名作为createElement的参数,就不列出来了。结果如下所示,左下角显示的是数据对象的相关内容。
在这里插入图片描述

2.2.3 VNode必须唯一

组件树中的VNode必须唯一,官方demo

2.3 JS语法
2.3.1 v-if
2.3.2 v-for
2.3.3 事件
2.3.4 插槽
2.4 JSX

这里是编写JSX风格的代码,然后利用Babel插件转化成JS风格,我没用,就不多做介绍。

2.5 函数式组件

待会学习下

3. 复杂案例

参考业务上的demo,做了一个简化的业务。

4. 总结

本文是我在认真学习了官网教程,并查阅了相关资料后,总结的结果。针对教程中部分晦涩的地方进行了扩展,教程中相关部分写的不错,因此我省略了并添加链接。欢迎大家留言交流。如果问题,欢迎斧正。

待续

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值