文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Vue3渲染器与编译器深入浅析

2023-02-01 18:00

关注

渲染器

相关概念

渲染器是Vue框架性能的核心,Vue3的渲染器不仅包含传统的Diff算法,还独创了快捷的路径更新方式,可以充分利用渲染器提供的信息,大大提升更新和渲染的性能;

组件可以通过函数JS对象来实现

// MyComponent 是一个对象
const MyComponent = {
  render() {
    return {
      tag: "div",
      props: {
        onClick: () => alert("hello"),
      },
      children: "click me",
    };
  },
};
function mountComponent(vnode, container) {
  // 调用组件函数,获取组件要渲染的内容(虚拟 DOM)
  const subtree = vnode.tag();
  // 递归地调用 renderer 渲染 subtree
  renderer(subtree, container);
}
// MyComponent 是一个函数
function renderer(vnode, container) {
  if (typeof vnode.tag === "string") {
    // 说明 vnode 描述的是标签元素
    // mountElement内部实现与下文的「实现renderer渲染器逻辑一致」
    mountElement(vnode, container);
  } else if (typeof vnode.tag === "function") {
    // 说明 vnode 描述的是组件
    mountComponent(vnode, container);
  }
}
function mountComponent(vnode, container) {
  // 调用组件函数,获取组件要渲染的内容(虚拟 DOM)
  const subtree = vnode.tag();
  // 递归地调用 renderer 渲染 subtree
  renderer(subtree, container);
}

render与renderer

实现renderer渲染器

function renderer(vnode, container) {
  // 使用 vnode.tag 作为标签名称创建对应的 DOM 元素
  const el = document.createElement(vnode.tag);
  // 遍历 vnode.props,将属性、事件添加到 DOM 元素
  for (const key in vnode.props) {
    if (/^on/.test(key)) {
      // 如果 key 以 on 开头,说明它是事件
      el.addEventListener(
        key.substr(2).toLowerCase(), // 事件名称 onClick ---> click
        vnode.props[key] // 事件处理函数
      );
    }
  }
  // 处理 children
  if (typeof vnode.children === "string") {
    // 如果 children 是字符串,说明它是元素的文本子节点
    el.appendChild(document.createTextNode(vnode.children));
  } else if (Array.isArray(vnode.children)) {
    // 递归地调用 renderer 函数渲染子节点,使用当前元素 el 作为挂载点
    vnode.children.forEach((child) => renderer(child, el));
  }
  // 将元素添加到挂载点下
  container.appendChild(el);
}

具体代码实现逻辑

角色解析

具体作用

Vue3特殊内置组件解析

<template>
   // Portal 把里面的内容挂载到 #app
  <Portal target="#app">
    <div class="overlay"></div>
  </Portal>
</template>

渲染器阶段分析

mount挂载阶段

mount就是将VNode挂载到真实DOM上

patch阶段

patch就是使用新的VNode和旧的VNode进行对比,用最少的资源实现DOM更新,也叫「打补丁」

简单实现

渲染器接受两个参数,要被渲染的VNode和挂载点(承载内容的container)

function createRenderer() {
  function render(vnode, container) {
    if (vnode) {
      // 存在旧节点  需要进行patch补丁更新
      patch(container._vnode, vnode, container);
    } else {
      if (container._vnode) {
        // 旧 vnode 存在,且新 vnode 不存在,此时渲染的是上一步中的节点值,说明是卸载(unmount)操作
        container.innerHTML = "";
      }
    }
    // 把 vnode 存储到 container._vnode 下,即后续渲染中的旧 vnode
    container._vnode = vnode;
  }
  return {
    render,
  };
}

编译器

编译器在模板编译时可以识别哪些是静态属性,哪些是动态属性,从而在编译生成代码时可以将这些信息附加到编译后代码中,这样可以避免渲染器花费力气去寻找变更点

相关概念

编译器和渲染器一样,不同之处在于编译器是将模板编译成渲染函数,而模板就是一个普通的字符串,编译器会分析该字符串并生成一个功能与之相同的渲染函数;
模板在Vue中体现在.vue文件中的<template>标签的内容,本身.vue文件就是一个组件,编译器会将模板内容编译成渲染函数并添加到<script>标签的组件对象上;

<template>
  <div @click="login">
    登录
  </div>
</template>
<script>
  export default {
    data() {
    },
    methods: {
      login: () => { }
    }
  }
</script>
//编译后
export default {
  data() {},
  methods: {
    login: () => { }
  },
  render() {
    return h('div', { onClick: login }, '登录')
  }
}

总结

通过将渲染器和编译器相配合,从而达到进一步提升性能的目的

组件的实现需要依赖于渲染器,模板的编译需要依赖于编译器,而且编译后的代码是根据渲染器和虚拟DOM的设计决定的,因此Vue中各个模块之间是相互关联、相互制约的;

模板工作原理:无论是模板还是直接手写渲染函数,对于一个组件来说,其渲染内容最终都是通过渲染函数产生的,然后渲染器再将渲染函数返回 的虚拟DOM渲染为真实DOM

以上就是Vue3渲染器与编译器深入浅析的详细内容,更多关于Vue3渲染器编译器的资料请关注编程网其它相关文章!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-前端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯