Vue.js设计与实现读书笔记七 第七章 渲染器的设计

7.1 渲染器与响应系统的结合

渲染器就是将vnode渲染到容器中,容器就是某个html节点,响应式实现一个简单的渲染器,这引入vue3中的effect和ref,这两个之前分析过,也可以用之前实现effect和ref

<div id="app"></div>

<script src="https://unpkg.com/@vue/reactivity@3.0.5/dist/reactivity.global.js"></script>
<script>

const { effect, ref } = VueReactivity

function renderer(domString, container) {
  container.innerHTML = domString
}

const count = ref(1)

effect(() => {
  renderer(`<h1>${count.value}</h1>`, document.getElementById('app'))
})

count.value++

effect 执行后,第一次渲染,然后track收集副作用函数,当count.vlue改变,导致trigger触发执行 副作用函数,第二次渲染

搞清几个概念
1.renderer是渲染器,包含render渲染器,hydrate
2.render是渲染器的行为,渲染,是动词,
3.Vnode是虚拟dom,即js描述html标签
4.container是容器,渲染函数渲染的节点为容器
5.mount是挂载,表示渲染器成功将Vnode,渲染到容器上了,完成一次渲染

渲染器的抽象实现

function createRenderer() {

  function patch(n1, n2, container) {

  }

  function render(vnode, container) {
		if (vnode) {
      // 新 vnode 存在,将其与旧 vnode 一起传递给 patch 函数进行打补丁
      patch(container._vnode, vnode, container)
    } else {
      if (container._vnode) {
        // 旧 vnode 存在,且新 vnode 不存在,说明是卸载(unmount)操作
        // 只需要将 container 内的 DOM 清空即可
        container.innerHTML = ''
      }
    }
    // 把 vnode 存储到 container._vnode 下,即后续渲染中的旧 vnode
    container._vnode = vnode
  }
  
  return {
    render
  }
}

const renderer = createRenderer()

// 首次渲染
renderer.render(vnode1, document.querySelector('#app'))
// 第二次渲染
renderer.render(vnode2, document.querySelector('#app'))
// 第三次渲染
renderer.render(null, document.querySelector('#app'))

当每一次渲染,会比较前一次和新的Vnode直接的差异,当新的Vnode为空,清空容器中的HTML,path函数承担,比较Vnode,还要挂载Vnode,是整个渲染器的核心

7.3 自定义渲染器

这里要解决的问题是,要将操作Dom的逻辑变成参数,提取出来,因为要设计一个多平台的渲染器,操作Dom的逻辑是浏览器专属的.创建dom,为标签插入字符,挂载到Dom上这些逻辑,都由用户传入,

function createRenderer(options) {

    const {
      createElement,
      insert,
      setElementText
    } = options
     // 挂载
    function mountElement(vnode, container) { // 将Vnode渲染到容器中
      const el = createElement(vnode.type) //根据Vnode创建一个Dom原生
      if (typeof vnode.children === 'string') { //如果是文本标签
        setElementText(el, vnode.children) // 将元素
      }
      insert(el, container) // 执行挂载
    }
// n1是旧Vnode n2是新的Vnode,
    function patch(n1, n2, container) {
      if (!n1) { // 当旧Vnode不存在,表示是第一渲染,直接调用渲染函数
        mountElement(n2, container)
      } else {
        //
      }
    }

    function render(vnode, container) {
      if (vnode) {
        // 新 vnode 存在,将其与旧 vnode 一起传递给 patch 函数进行打补丁
        patch(container._vnode, vnode, container)
      } else {
        if (container._vnode) {
          // 旧 vnode 存在,且新 vnode 不存在,说明是卸载(unmount)操作
          // 只需要将 container 内的 DOM 清空即可
          container.innerHTML = ''
        }
      }
      // 把 vnode 存储到 container._vnode 下,即后续渲染中的旧 vnode
      container._vnode = vnode
    }

    return {
      render
    }
  }

  const vnode = {
    type: 'h1',
    children: 'hello'
  }

  // renderer.render(vnode, document.querySelector('#app'))


  const renderer2 = createRenderer({
    createElement(tag) {
      console.log(`创建元素 ${tag}`)
      return { tag }
    },
    setElementText(el, text) {
      console.log(`设置 ${JSON.stringify(el)} 的文本内容:${text}`)
      el.text = text
    },
    insert(el, parent, anchor = null) {
      console.log(`${JSON.stringify(el)} 添加到 ${JSON.stringify(parent)}`)
      parent.children = el
    }
  })

  const container = { type: 'root' }
  renderer2.render(vnode, container)

当然这里的逻辑是第一次渲染的,path函数没有考虑多次渲染,

问题总结:

(二十三)渲染器有哪些基本概念?虚拟DOM的结构是?为什么造成DOM的方法都被当option选项传入?
(1)
搞清几个概念
1.renderer是渲染器,包含render渲染器,hydrate
2.render是渲染器的行为,渲染,是动词,
3.Vnode是虚拟dom,即js描述html标签
4.container是容器,渲染函数渲染的节点为容器
5.mount是挂载,表示渲染器成功将Vnode,渲染到容器上了,完成一次渲染
6.patch(n1,n2,container)是渲染器的核心,他是处理新旧Vnode的和DOM的核心
n1表示旧vnode,n2表示新vnode,container表示:容器
(2) vnode是个对象,有非常重要的3个属性,type表示节点类型,props表示节点的属性,children表示子节点的类型,渲染器围绕着这type和children不同变化来处理的
例如:当type为string类型,表示是一个普通标签,children为string表示是标签的内容

let vnode={type:String,props:,children:}

(3)因为需要多平台渲染,为了设计一个通用的渲染器

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值