首页 > 其他分享 >《Vue.js 设计与实现》读书笔记 - 第7章、渲染器的设计

《Vue.js 设计与实现》读书笔记 - 第7章、渲染器的设计

时间:2023-02-02 15:23:35浏览次数:45  
标签:function el Vue container 读书笔记 vnode 渲染器 patch

第7章、渲染器的设计

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

  • 渲染器需要有跨平台的能力。
  • 在浏览器端会渲染为真实的 DOM 元素。
const { effect, ref } = VueReactivity // VueReactivity 是前几章实现的响应式代码

function renderer(domString, container) {
  container.innerHTML = domString
}
const count = ref(1)
effect(() => {
  renderer(`<h1>${count.value}</h1>`, document.getElementById('app'))
})

count.value++

通过简单的 innerHTML 可以实现渲染器,如果把渲染器放入响应式函数,就可以实现自动渲染。

7.2 渲染器的基本概念

  • renderer 渲染器
  • render 动词 渲染
  • virtual DOM,vdom 虚拟 DOM
  • virtual node,vnode,虚拟 node,构成 vdom 的节点
  • 挂载,mount,虚拟 DOM 渲染为真实 DOM
  • 挂载点,真实 DOM 挂载的位置,一个 DOM 元素,一般用 container 表示。

我们实现 createRenderer 函数,它会创建不同平台的渲染器。其中 render 用于浏览器。渲染分两种情况,挂载和后续渲染(存在旧节点),我们在内部使用 patch 去实现具体渲染(暂未实现)。

function createRenderer() {
  // n1 旧node
  // n2 新node
  // container 容器
  // patch可以用户挂载 也可以用于后续渲染
  function patch(n1, n2, container) {}
 
  function render(vnode, container) {
    if (vnode) {
      // 如果有新 vnode 就和旧 vnode 一起用 patch 处理
      patch(container._vnode, node, container)
    } else {
      // 没有新 vnode 但是有旧 vnode 直接清空 DOM 即可
      if (container._vnode) {
        container.innerHTML = ''
      }
    }
    // 把旧 vnode 缓存到 container
    container._vnode = vnode
  }

  function hydrate(vnode, container) {
    // 服务端渲染
  }

  return {
    render,
    hydrate,
  }
}

7.3 自定义渲染器

把平台相关的函数提取出来,并通过参数传入,然后封装多平台通用的渲染器。

如下,实现了 mountElement 函数,用于 patch 函数在挂载时使用,而挂载要依赖平台的实现,比如创建元素,插入元素,我们把这些通过 options 统一传入。

function createRenderer(options) {
  const { createElement, insert, setElementText } = options

  function mountElement(vnode, container) {
    const el = createElement(vnode.type)

    if (typeof vnode.children === 'string') {
      setElementText(el, vnode.children)
    }
    insert(el, container)
  }

  // n1:旧node,n2:新node,container:容器
  function patch(n1, n2, container) {
    if (!n1) {
      // 挂载
      mountElement(n2, container)
    } else {
      // 打补丁,暂时省略
    }
  }

  function render(vnode, container) {
    if (vnode) {
      // 如果有新 vnode 就和旧 vnode 一起用 patch 处理
      patch(container._vnode, vnode, container)
    } else {
      // 没有新 vnode 但是有旧 vnode 直接清空 DOM 即可
      if (container._vnode) {
        container.innerHTML = ''
      }
    }
    // 把旧 vnode 缓存到 container
    container._vnode = vnode
  }

  function hydrate(vnode, container) {
    // 服务端渲染
  }

  return {
    render,
    hydrate,
  }
}

当我们实现浏览器端的渲染器时,可以传入浏览器的 API 实现的函数。

const renderer = createRenderer({
  createElement(tag) {
    return document.createElement(tag)
  },
  setElementText(el, text) {
    el.textContent = text
  },
  insert(el, parent, anchor = null) {
    parent.insertBefore(el, anchor)
  },
})

renderer.render(
  {
    type: 'h1',
    children: 'hello',
  },
  document.getElementById('app')
)

如上代码,可以在页面渲染出 h1 标签显示 hello。我们也可以通过传入自己实现的对应 API 实现自定义渲染器。

const rendererCustom = 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
  },
})

rendererCustom.render(
  {
    type: 'h1',
    children: 'hello',
  },
  { type: 'root' }
)

.

标签:function,el,Vue,container,读书笔记,vnode,渲染器,patch
From: https://www.cnblogs.com/wenruo/p/17086112.html

相关文章

  • vue添加css样式的方式
    vue添加css样式的方式1、在.vue文件中引入css<stylescopedlang="scss"type="text/scss">@import"../css/style.css";</style> 2、直接在<style>中写......
  • vue.js客服系统实时聊天项目开发(十七)解决url get传参后进行base64解密问题
    有些参数需要在url的GET里传递,但是为了防止特殊字符问题,我转成了base64编码。但是js进行解码的时候,总是报错:报错:Failedtoexecute'atob'on'Window':Thestringto......
  • 解决vite+vue3混合开发白屏问题
    开发环境:vite4.0+vue3.2使用场景:vite打包后将包嵌入app使用。问题描述:打包后app显示白屏。解决方案:默认的构建目标是能支持原生ESM语法的script标签、原生ESM动态导......
  • vue 获取 DOM 元素的方法
    1.原生js获取DOM节点document.querySelector(选择器)document.getElementById(id选择器)document.getElementsByClassName(class选择器)....2.vue2中获取当前组......
  • 快速上手vue前端存储库、全局状态管理工具pinia
    pinia是什么,为什么我们要使用pinia?pinia是vue全局状态管理工具,类似vueX,用于全局的数据状态存储、修改变更等等相较于vueX,pinia的使用较为简单,轻量级,上手容易,干掉了vue......
  • 总结了 Vue3 的七种组件通信方式,别再说不会组件通信了
    总结了Vue3的七种组件通信方式,别再说不会组件通信了播报文章网格化软件高品伟业2022-04-1916:35山东关注 写在前面  本篇文章是全部采用的......
  • vue-plugin-hiprint
    vue-plugin-hiprint(基于hiprint2.5.4)当时只是为了方便我(并非hiprint原作者)在vue项目中引入使用,所以以此命名。此插件仅仅是一个JavaScript【工具库】而非Vue【组件库......
  • ts找不到 ./APP.vue
    在使用vue3+ts中遇到如下问题解决方法:查看跟App.vue同级目录有没有env.d.ts文件,如果有则给里面添加以下代码declaremodule"*.vue"{importtype{DefineComp......
  • 最好用的 6 款 Vue 拖拽组件库推荐
    Vue拖拽组件库(drag-and-drop)组件在使用Vue框架开发中非常常见的需求,做个内容行排序,拖拽小组件到网页上这类都需要用到拖拽组件。本文记录了我自己用过的6款Vue拖拽......
  • Vue3 安裝v-viewer
    一、执行命令npminstallv-viewer@next二、在main.js中引入//v-viewer:图片预览、缩放、翻转import'viewerjs/dist/viewer.css'importViewerfrom'v-viewer' ......