如何用Vue实现一个渲染引擎

这篇文章主要介绍“如何用Vue实现一个渲染引擎”,在日常操作中,相信很多人在如何用Vue实现一个渲染引擎问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”如何用Vue实现一个渲染引擎”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

成都创新互联长期为上千家客户提供的网站建设服务,团队从业经验10年,关注不同地域、不同群体,并针对不同对象提供差异化的产品和服务;打造开放共赢平台,与合作伙伴共同营造健康的互联网生态环境。为阎良企业提供专业的网站建设、成都做网站,阎良网站改版等技术服务。拥有10多年丰富建站经验和众多成功案例,为您定制开发。

前言

当我们得到 render 函数之后,接下来就该进入到真正的挂载阶段了:

挂载 -> 实例化渲染 Watcher -> 执行 updateComponent 方法 -> 执行 render 函数生成 VNode -> 执行 patch 进行首次渲染 -> 递归遍历 VNode 创建各个节点并处理节点上的普通属性和指令 -> 如果节点是自定义组件则创建组件实例 -> 进行组件的初始化、挂载 -> 最终所有 VNode 变成真实的 DOM 节点并替换掉页面上的模版内容 -> 完成初始渲染

目标

所以,本篇文章目标就是实现上面描述的整个过成,完成初始渲染。整个过程中涉及如下知识点:

  • render helper

  • VNode

  • patch 初始渲染

  • 指令(v-model、v-bind、v-on)的处理

  • 实例化子组件

  • 插槽的处理

实现

接下来就正式进入代码实现过程,一步步实现上述所有内容,完成页面的初始渲染。

mount

/src/compiler/index.js

/**  * 编译器  */ export default function mount(vm) {   if (!vm.$options.render) { // 没有提供 render 选项,则编译生成 render 函数     // ...   }   mountComponent(vm) } 复制代码

mountComponent

/src/compiler/mountComponent.js

/**  * @param {*} vm Vue 实例  */ export default function mountComponent(vm) {   // 更新组件的的函数   const updateComponent = () => {     vm._update(vm._render())   }   // 实例化一个渲染 Watcher,当响应式数据更新时,这个更新函数会被执行   new Watcher(updateComponent) } 复制代码

vm._render

/src/compiler/mountComponent.js

/**  * 负责执行 vm.$options.render 函数  */ Vue.prototype._render = function () {   // 给 render 函数绑定 this 上下文为 Vue 实例   return this.$options.render.apply(this) } 复制代码

render helper

/src/compiler/renderHelper.js

/**  * 在 Vue 实例上安装运行时的渲染帮助函数,比如 _c、_v,这些函数会生成 Vnode  * @param {VueContructor} target Vue 实例  */ export default function renderHelper(target) {   target._c = createElement   target._v = createTextNode } 复制代码

createElement

/src/compiler/renderHelper.js

/**  * 根据标签信息创建 Vnode  * @param {string} tag 标签名   * @param {Map} attr 标签的属性 Map 对象  * @param {Array<Render>} children 所有的子节点的渲染函数  */ function createElement(tag, attr, children) {   return VNode(tag, attr, children, this) } 复制代码

createTextNode

/src/compiler/renderHelper.js

/**  * 生成文本节点的 VNode  * @param {*} textAst 文本节点的 AST 对象  */ function createTextNode(textAst) {   return VNode(null, null, null, this, textAst) } 复制代码

VNode

/src/compiler/vnode.js

/**  * VNode  * @param {*} tag 标签名  * @param {*} attr 属性 Map 对象  * @param {*} children 子节点组成的 VNode  * @param {*} text 文本节点的 ast 对象  * @param {*} context Vue 实例  * @returns VNode  */ export default function VNode(tag, attr, children, context, text = null) {   return {     // 标签     tag,     // 属性 Map 对象     attr,     // 父节点     parent: null,     // 子节点组成的 Vnode 数组     children,     // 文本节点的 Ast 对象     text,     // Vnode 的真实节点     elm: null,     // Vue 实例     context   } } 复制代码

vm._update

/src/compiler/mountComponent.js

Vue.prototype._update = function (vnode) {   // 老的 VNode   const prevVNode = this._vnode   // 新的 VNode   this._vnode = vnode   if (!prevVNode) {     // 老的 VNode 不存在,则说明时首次渲染根组件     this.$el = this.__patch__(this.$el, vnode)   } else {     // 后续更新组件或者首次渲染子组件,都会走这里     this.$el = this.__patch__(prevVNode, vnode)   } } 复制代码

安装 __patch__、render helper

/src/index.js

/**  * 初始化配置对象  * @param {*} options   */ Vue.prototype._init = function (options) {   // ...   initData(this)   // 安装运行时的渲染工具函数   renderHelper(this)   // 在实例上安装 patch 函数   this.__patch__ = patch   // 如果存在 el 配置项,则调用 $mount 方法编译模版   if (this.$options.el) {     this.$mount()   } } 复制代码

patch

/src/compiler/patch.js

/**  * 初始渲染和后续更新的入口  * @param {VNode} oldVnode 老的 VNode  * @param {VNode} vnode 新的 VNode  * @returns VNode 的真实 DOM 节点  */ export default function patch(oldVnode, vnode) {   if (oldVnode && !vnode) {     // 老节点存在,新节点不存在,则销毁组件     return   }   if (!oldVnode) { // oldVnode 不存在,说明是子组件首次渲染     createElm(vnode)   } else {     if (oldVnode.nodeType) { // 真实节点,则表示首次渲染根组件       // 父节点,即 body       const parent = oldVnode.parentNode       // 参考节点,即老的 vnode 的下一个节点 —— script,新节点要插在 script 的前面       const referNode = oldVnode.nextSibling       // 创建元素       createElm(vnode, parent, referNode)       // 移除老的 vnode       parent.removeChild(oldVnode)     } else {       console.log('update')     }   }   return vnode.elm } 复制代码

createElm

/src/compiler/patch.js

/**  * 创建元素  * @param {*} vnode VNode  * @param {*} parent VNode 的父节点,真实节点  * @returns   */ function createElm(vnode, parent, referNode) {   // 记录节点的父节点   vnode.parent = parent   // 创建自定义组件,如果是非组件,则会继续后面的流程   if (createComponent(vnode)) return   const { attr, children, text } = vnode   if (text) { // 文本节点     // 创建文本节点,并插入到父节点内     vnode.elm = createTextNode(vnode)   } else { // 元素节点     // 创建元素,在 vnode 上记录对应的 dom 节点     vnode.elm = document.createElement(vnode.tag)     // 给元素设置属性     setAttribute(attr, vnode)     // 递归创建子节点     for (let i = 0, len = children.length; i < len; i++) {       createElm(children[i], vnode.elm)     }   }   // 如果存在 parent,则将创建的节点插入到父节点内   if (parent) {     const elm = vnode.elm     if (referNode) {       parent.insertBefore(elm, referNode)     } else {       parent.appendChild(elm)     }   } }

到此,关于“如何用Vue实现一个渲染引擎”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注创新互联网站,小编会继续努力为大家带来更多实用的文章!

当前题目:如何用Vue实现一个渲染引擎
URL标题:https://www.cdcxhl.com/article44/gshsee.html

成都网站建设公司_创新互联,为您提供搜索引擎优化网站建设关键词优化标签优化云服务器网页设计公司

广告

声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联

搜索引擎优化