中文字幕日韩精品一区二区免费_精品一区二区三区国产精品无卡在_国精品无码专区一区二区三区_国产αv三级中文在线

如何用Vue實現(xiàn)一個渲染引擎

這篇文章主要介紹“如何用Vue實現(xiàn)一個渲染引擎”,在日常操作中,相信很多人在如何用Vue實現(xiàn)一個渲染引擎問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”如何用Vue實現(xiàn)一個渲染引擎”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

成都創(chuàng)新互聯(lián)長期為上千家客戶提供的網(wǎng)站建設(shè)服務,團隊從業(yè)經(jīng)驗10年,關(guān)注不同地域、不同群體,并針對不同對象提供差異化的產(chǎn)品和服務;打造開放共贏平臺,與合作伙伴共同營造健康的互聯(lián)網(wǎng)生態(tài)環(huán)境。為閻良企業(yè)提供專業(yè)的網(wǎng)站建設(shè)、成都做網(wǎng)站,閻良網(wǎng)站改版等技術(shù)服務。擁有10多年豐富建站經(jīng)驗和眾多成功案例,為您定制開發(fā)。

前言

當我們得到 render 函數(shù)之后,接下來就該進入到真正的掛載階段了:

掛載 -> 實例化渲染 Watcher -> 執(zhí)行 updateComponent 方法 -> 執(zhí)行 render 函數(shù)生成 VNode -> 執(zhí)行 patch 進行首次渲染 -> 遞歸遍歷 VNode 創(chuàng)建各個節(jié)點并處理節(jié)點上的普通屬性和指令 -> 如果節(jié)點是自定義組件則創(chuàng)建組件實例 -> 進行組件的初始化、掛載 -> 最終所有 VNode 變成真實的 DOM 節(jié)點并替換掉頁面上的模版內(nèi)容 -> 完成初始渲染

目標

所以,本篇文章目標就是實現(xiàn)上面描述的整個過成,完成初始渲染。整個過程中涉及如下知識點:

  • render helper

  • VNode

  • patch 初始渲染

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

  • 實例化子組件

  • 插槽的處理

實現(xiàn)

接下來就正式進入代碼實現(xiàn)過程,一步步實現(xiàn)上述所有內(nèi)容,完成頁面的初始渲染。

mount

/src/compiler/index.js

/**  * 編譯器  */ export default function mount(vm) {   if (!vm.$options.render) { // 沒有提供 render 選項,則編譯生成 render 函數(shù)     // ...   }   mountComponent(vm) } 復制代碼

mountComponent

/src/compiler/mountComponent.js

/**  * @param {*} vm Vue 實例  */ export default function mountComponent(vm) {   // 更新組件的的函數(shù)   const updateComponent = () => {     vm._update(vm._render())   }   // 實例化一個渲染 Watcher,當響應式數(shù)據(jù)更新時,這個更新函數(shù)會被執(zhí)行   new Watcher(updateComponent) } 復制代碼

vm._render

/src/compiler/mountComponent.js

/**  * 負責執(zhí)行 vm.$options.render 函數(shù)  */ Vue.prototype._render = function () {   // 給 render 函數(shù)綁定 this 上下文為 Vue 實例   return this.$options.render.apply(this) } 復制代碼

render helper

/src/compiler/renderHelper.js

/**  * 在 Vue 實例上安裝運行時的渲染幫助函數(shù),比如 _c、_v,這些函數(shù)會生成 Vnode  * @param {VueContructor} target Vue 實例  */ export default function renderHelper(target) {   target._c = createElement   target._v = createTextNode } 復制代碼

createElement

/src/compiler/renderHelper.js

/**  * 根據(jù)標簽信息創(chuàng)建 Vnode  * @param {string} tag 標簽名   * @param {Map} attr 標簽的屬性 Map 對象  * @param {Array<Render>} children 所有的子節(jié)點的渲染函數(shù)  */ function createElement(tag, attr, children) {   return VNode(tag, attr, children, this) } 復制代碼

createTextNode

/src/compiler/renderHelper.js

/**  * 生成文本節(jié)點的 VNode  * @param {*} textAst 文本節(jié)點的 AST 對象  */ function createTextNode(textAst) {   return VNode(null, null, null, this, textAst) } 復制代碼

VNode

/src/compiler/vnode.js

/**  * VNode  * @param {*} tag 標簽名  * @param {*} attr 屬性 Map 對象  * @param {*} children 子節(jié)點組成的 VNode  * @param {*} text 文本節(jié)點的 ast 對象  * @param {*} context Vue 實例  * @returns VNode  */ export default function VNode(tag, attr, children, context, text = null) {   return {     // 標簽     tag,     // 屬性 Map 對象     attr,     // 父節(jié)點     parent: null,     // 子節(jié)點組成的 Vnode 數(shù)組     children,     // 文本節(jié)點的 Ast 對象     text,     // Vnode 的真實節(jié)點     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 {     // 后續(xù)更新組件或者首次渲染子組件,都會走這里     this.$el = this.__patch__(prevVNode, vnode)   } } 復制代碼

安裝 __patch__、render helper

/src/index.js

/**  * 初始化配置對象  * @param {*} options   */ Vue.prototype._init = function (options) {   // ...   initData(this)   // 安裝運行時的渲染工具函數(shù)   renderHelper(this)   // 在實例上安裝 patch 函數(shù)   this.__patch__ = patch   // 如果存在 el 配置項,則調(diào)用 $mount 方法編譯模版   if (this.$options.el) {     this.$mount()   } } 復制代碼

patch

/src/compiler/patch.js

/**  * 初始渲染和后續(xù)更新的入口  * @param {VNode} oldVnode 老的 VNode  * @param {VNode} vnode 新的 VNode  * @returns VNode 的真實 DOM 節(jié)點  */ export default function patch(oldVnode, vnode) {   if (oldVnode && !vnode) {     // 老節(jié)點存在,新節(jié)點不存在,則銷毀組件     return   }   if (!oldVnode) { // oldVnode 不存在,說明是子組件首次渲染     createElm(vnode)   } else {     if (oldVnode.nodeType) { // 真實節(jié)點,則表示首次渲染根組件       // 父節(jié)點,即 body       const parent = oldVnode.parentNode       // 參考節(jié)點,即老的 vnode 的下一個節(jié)點 —— script,新節(jié)點要插在 script 的前面       const referNode = oldVnode.nextSibling       // 創(chuàng)建元素       createElm(vnode, parent, referNode)       // 移除老的 vnode       parent.removeChild(oldVnode)     } else {       console.log('update')     }   }   return vnode.elm } 復制代碼

createElm

/src/compiler/patch.js

/**  * 創(chuàng)建元素  * @param {*} vnode VNode  * @param {*} parent VNode 的父節(jié)點,真實節(jié)點  * @returns   */ function createElm(vnode, parent, referNode) {   // 記錄節(jié)點的父節(jié)點   vnode.parent = parent   // 創(chuàng)建自定義組件,如果是非組件,則會繼續(xù)后面的流程   if (createComponent(vnode)) return   const { attr, children, text } = vnode   if (text) { // 文本節(jié)點     // 創(chuàng)建文本節(jié)點,并插入到父節(jié)點內(nèi)     vnode.elm = createTextNode(vnode)   } else { // 元素節(jié)點     // 創(chuàng)建元素,在 vnode 上記錄對應的 dom 節(jié)點     vnode.elm = document.createElement(vnode.tag)     // 給元素設(shè)置屬性     setAttribute(attr, vnode)     // 遞歸創(chuàng)建子節(jié)點     for (let i = 0, len = children.length; i < len; i++) {       createElm(children[i], vnode.elm)     }   }   // 如果存在 parent,則將創(chuàng)建的節(jié)點插入到父節(jié)點內(nèi)   if (parent) {     const elm = vnode.elm     if (referNode) {       parent.insertBefore(elm, referNode)     } else {       parent.appendChild(elm)     }   } }

到此,關(guān)于“如何用Vue實現(xiàn)一個渲染引擎”的學習就結(jié)束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續(xù)學習更多相關(guān)知識,請繼續(xù)關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>

當前題目:如何用Vue實現(xiàn)一個渲染引擎
URL標題:http://www.rwnh.cn/article44/gshsee.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供搜索引擎優(yōu)化、網(wǎng)站建設(shè)關(guān)鍵詞優(yōu)化、標簽優(yōu)化云服務器、網(wǎng)頁設(shè)計公司

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

搜索引擎優(yōu)化
大埔区| 宝应县| 静宁县| 紫金县| 吉安市| 曲麻莱县| 惠来县| 石屏县| 阿勒泰市| 抚州市| 津市市| 巫溪县| 石屏县| 安仁县| 汉中市| 玛多县| 邳州市| 丹棱县| 岱山县| 宜昌市| 瑞安市| 邮箱| 阳新县| 库尔勒市| 乌鲁木齐市| 淮南市| 富平县| 辰溪县| 德令哈市| 崇礼县| 辰溪县| 绵阳市| 东丰县| 南乐县| 宜君县| 黔西县| 衡南县| 铜川市| 巩义市| 周口市| 海林市|