《vue.js的设计与实现》7-8章小结

一、渲染器基本概念

用createRenderer()创建渲染器,在响应式系统的副作用函数中执行渲染器的渲染函数。渲染函数接收两个参数,一个是虚拟vnode,一个是挂载点,用来指定具体的挂载位置。当第一次执行副作用函数即第一次渲染时,只需要创建新的dom元素,相当于挂载。当再次渲染的时候,渲染器就会使用newvnode与上一次渲染的oldvnode进行比较,进行patch更新的操作。当渲染函数的第一个参数vnode为空的时候,相当于卸载操作,即渲染器需要清空容器。

二、属性的渲染

<div id="foo">
    <p>hello</p>
</div>

如上所示的html模版会被编译为

const vnode = {
    type:'div',
    props:{
        id:'foo'
    },
    children:[
    {
        type:'p',
        children:'hello'
    }]
}

使用props来描述元素的属性,设置属性的方法有两种,一种是HTML Attributes,设置时为:

el.setAttribute('id','foo')

另一种是DOM Properties,设置时为:

el.id = 'foo'

对于普通的html文件来说,当浏览器解析html代码后,会自动分析HTML Attributes并设置合适的DOM Properties。HTML Attributes的作用是设置与之对应的DOM Properties的初始值,当值发生改变时,DOM Properties存储着当前值,而通过getAttribute函数得到的仍为初始值。
由于使用setAttribute函数设置的值总是会被字符串化,渲染器会优先使用DOM Properties来设置属性,当属性为布尔类型且值为空时就手动矫正为true,如果属性没有对应的DOM Properties,则再使用setAttribute函数完成属性设置。

三、卸载与更新操作

卸载:在调用createElement函数创建真实dom元素时,会把真实dom元素赋值给vnode.el属性。当卸载操作发生时,就根据虚拟节点对象vnode.el获取真实dom元素,并调用removeChild函数将其从父元素中移除。
更新:在更新操作中,要判断新旧节点的类型,如果新旧节点的type不同,则之间卸载旧节点,挂载新节点。还要判断节点的类型,如果是字符串类型,说明是普通标签元素,如果是对象,说明是组件,由此要调用不同的更新方法。

四、事件的处理

在虚拟节点中描述事件,写在props中,以字符串on开头的属性都是事件

const vnode = {
    type:'div',
    props:{
        id:'foo',
        onClick:()=>{
            alert('clicked')
        }
    },
    children:[
    {
        type:'p',
        children:'hello'
    }]
}

将事件添加到dom元素上只要调用addEventListener函数 来绑定事件即可。
更新事件采用一个伪造的事件处理函数invoker,然后把真正的事件处理函数设置为invoker.value的值,这样当更新事件的时候,只需要更新invoker.value的值即可。考虑到一个元素可以同时绑定多个事件,用一个对象来存储事件,根据事件名称来获取invoker。同时,考虑到同一类型的事件可以有多个,用数组来描述一个类型的事件,并在patch时遍历数组进行执行。
当触发一个事件后,渲染器的更新操作会在事件冒泡之前进行,这样如果在更新时有增加对父元素的事件绑定,父元素事件就会被触发,引起一些问题。因此,要屏蔽所有绑定事件晚于事件触发事件的事件处理函数的执行。

五、子节点的挂载与更新

对一个元素来说,子节点有三种情况:
1、没有子节点,即vnode.children = null
2、有文本子节点,此时vnode.children值为字符串,代表文本的内容
3、其他情况如有元素子节点等都用数组来表示
分情况进行讨论:
1、当新子节点为文本节点,如果没有旧子节点或旧子节点为文本节点,只要将新的文本内容设置给容器即可。如果旧子节点是数组,就要遍历卸载。
2、当新子节点是数组,如果没有旧子节点或旧子节点为文本节点,只要将容器清空,并逐个将新子节点挂载。如果旧子节点是数组,则要进行diff算法比对。
3、当新子节点是null,旧子节点是文本节点就清空文本内容,是数组就遍历卸载。

六、Fragment类型

Fragment(片段)是vue3新增的一个vnode类型,用这个类型可以让vue3支持多根节点模版,这在vue2中是不支持的,只能在父组件中用v-for渲染多个子组件达到目的。

<template>
  <li>1</li>
  <li>2</li>
  <li>3</li>
</template>

对应的vnode:

const Fragment = Symbol()
const vnode = {
    type:Fragment,
    children:[
    {type:'li',children:'1'},
    {type:'li',children:'2'},
    {type:'li',children:'3'}
    ]
}

当渲染器渲染Fragment类型的虚拟节点时,本身不会渲染任何内容,只会渲染Fragment的子节点。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值