摘要:關(guān)于前端框架大家都有了解,或多或少的使用過,比如,,等等。那么你是否也想自己手寫一個(gè)的前端框架呢,我們從入手,手把手教你寫基于的前端框架,在整個(gè)編寫的過程中,希望大家學(xué)習(xí)更多,理解更多。本節(jié)我們以打包工具結(jié)合轉(zhuǎn)換插件實(shí)現(xiàn)數(shù)據(jù)的抽象。
關(guān)于MVVM前端框架大家都有了解,或多或少的使用過,比如Angular,React,VUE等等。那么你是否也想自己手寫一個(gè)MVVM的前端框架呢,我們從Virtual DOM入手,手把手教你寫基于Virtual DOM的前端框架,在整個(gè)編寫的過程中,希望大家學(xué)習(xí)更多,理解更多。
Github代碼: https://github.com/chalecao/v...
真實(shí)的DOM是網(wǎng)頁上的文檔對象模型,由一個(gè)個(gè)HTML元素節(jié)點(diǎn)構(gòu)成的樹形結(jié)構(gòu)。
如圖中所示,我們用JS創(chuàng)建出來的節(jié)點(diǎn)就是虛擬節(jié)點(diǎn),Virtual node,當(dāng)然由這些虛擬節(jié)點(diǎn)vd構(gòu)成的樹形結(jié)構(gòu)就稱為虛擬DOM,Virtual DOM。我們本節(jié)課介紹的就是要如何創(chuàng)建這樣的虛擬DOM。
章節(jié)2: 如何構(gòu)建VirtualDOM首先我們需要分析一個(gè)node節(jié)點(diǎn)的構(gòu)成,比如他的節(jié)點(diǎn)類型type,節(jié)點(diǎn)屬性的集合props,子元素的集合。這樣我們就可以抽象一個(gè)數(shù)據(jù)模型來表示這個(gè)節(jié)點(diǎn)。虛擬DOM是由許多虛擬節(jié)點(diǎn)按照層級結(jié)構(gòu)組合起來的,那么我們實(shí)現(xiàn)虛擬節(jié)點(diǎn)的數(shù)據(jù)模型抽象之后,就可以構(gòu)建虛擬DOM的數(shù)據(jù)模型抽象。
手工實(shí)現(xiàn)DOM模型構(gòu)建不太合理,我們可以借助JSX的工具來完成這個(gè)轉(zhuǎn)換。本節(jié)我們以rollup打包工具結(jié)合babel轉(zhuǎn)換插件實(shí)現(xiàn)數(shù)據(jù)的抽象。具體代碼配置參考:github中package.json配置和rollup.config.js
const vdom = ()hello
上面我們定義的vdom片段采用JSX處理器處理后如下面代碼:
/* fed123.com */ "use strict"; var vdom = vnode( "div", { id: "_Q5", style: "border: 1px solid red;" }, vnode( "div", { style: "text-align: center; margin: 36px auto 18px; width: 160px; line-height: 0;" }, vnode("img", { src: "https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_160x56dp.png", height: "56", style: "border: none; margin: 8px 0px;" }), "google" ) );
是不是很好理解,JSX編譯后會(huì)自動(dòng)根據(jù)定義好的語法格式提取出元素的類型和屬性和子元素,并填入vnode方法中,我們只需要實(shí)現(xiàn)vnode方法就可以。我們可以編寫vnode方法用于構(gòu)建虛擬節(jié)點(diǎn)的模型,編寫createElement方法用于根據(jù)vnode模型創(chuàng)建元素。并且把vnode的子元素追加到父元素上,形成樹形層級結(jié)構(gòu)。
function vnode(type, props, ...children) { return { type, props, children }; } function createElement(node) { if (typeof node === "string") { return document.createTextNode(node); } const $el = document.createElement(node.type); node.children .map(createElement) .forEach($el.appendChild.bind($el)); return $el; } document.body.appendChild(createElement(vdom));
這樣我們就完成了虛擬節(jié)點(diǎn)vnode和虛擬vDOM的構(gòu)建。
章節(jié)3: Diff VirtualDOM 與Update DOM如圖展示了最簡單的一層DOM的結(jié)構(gòu)變化,無非也就這么幾種:增加元素節(jié)點(diǎn)、修改節(jié)點(diǎn),刪除節(jié)點(diǎn)。我們可以基于DOM API來實(shí)現(xiàn)這些基本的操作,代碼如下:
function updateElement($parent, newnode, oldnode) { var index = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0; if (!newnode) { $parent.removeChild($parent.childNodes[index]); } else if (!oldnode) { $parent.appendChild(createElement(newnode)); } else if (isChange(newnode, oldnode)) { $parent.replaceChild(createElement(newnode), $parent.childNodes[index]); } else if (newnode.type) { var newL = newnode.children.length; var oldL = oldnode.children.length; for (var i = 0; i < newL || i < oldL; i++) { updateElement($parent.childNodes[index], newnode.children[i], oldnode.children[i], i); } } }
上面的代碼中我們實(shí)際上是把diff VirtualDOM 和update vdom放在一起處理了,采用了深度優(yōu)先遍歷的算法,從根節(jié)點(diǎn)優(yōu)先查到子節(jié)點(diǎn),判斷子節(jié)點(diǎn)是否變化,有變化就進(jìn)行變更處理,然后再回到上級節(jié)點(diǎn)。
章節(jié)4: 處理DOM屬性和事件綁定{ type: “div”, props: {“style”: ”…”}, children: [ {type: “img”, props: {“src”: ”…”} ]}
上面我們抽取的vnode的模型中已經(jīng)把props拿出來了,我們這里需要把這些樣式設(shè)置到對應(yīng)元素上就好了。我們先看下元素的屬性變化有哪幾種情況:
如上,元素屬性可以增加可以減少,我們通過DOM API實(shí)現(xiàn)屬性的更新操作,代碼如下:
//handle props function setProp($el, name, value) { if (typeof value == "boolean") { handleBoolProp($el, name, value); } else { $el.setAttribute(name, value); } } function handleBoolProp($el, name, value) { if (!!value) { $el.setAttribute(name, value); $el[name] = !!value; } else { $el[name] = !!value; } } function removeProp($el, name, value) { if (typeof value == "boolean") { $el[name] = false; } $el.removeAttribute(name, value); } function updateProp($el, name, newvalue, oldValue) { if (!newvalue) { removeProp($el, name, oldValue); } else if (!oldValue || newvalue != oldValue) { setProp($el, name, newvalue); } } function updateProps($el) { var newprops = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; var oldProps = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; var _props = Object.assign({}, newprops, oldProps); Object.keys(_props).forEach(function (key) { updateProp($el, key, newprops[key], oldProps[key]); }); }
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/107714.html
摘要:和刷新函數(shù)是一對多的關(guān)系,即一個(gè)可以有任意多個(gè)處理它的回調(diào)函數(shù)刷新函數(shù),比如和兩個(gè)指令共用一個(gè)數(shù)據(jù)模型字段。添加數(shù)據(jù)訂閱實(shí)現(xiàn)方式為建立緩存回調(diào)函數(shù)的數(shù)組緩存回調(diào)函數(shù)當(dāng)數(shù)據(jù)模型的字段發(fā)生改變時(shí),就會(huì)觸發(fā)緩存數(shù)組中訂閱了的所有回調(diào)。 MVVM 是 Web 前端一種非常流行的開發(fā)模式,利用 MVVM 可以使我們的代碼更專注于處理業(yè)務(wù)邏輯而不是去關(guān)心 DOM 操作。目前著名的 MVVM 框架有...
摘要:發(fā)布訂閱現(xiàn)在每個(gè)人應(yīng)該都用微信吧,一個(gè)人可以關(guān)注多個(gè)公眾號,多個(gè)人可以同時(shí)關(guān)注相同的公眾號。公眾號每周都會(huì)更新內(nèi)容,并推送給我們,把寫好的文章在微信管理平臺更新就好了,點(diǎn)擊推送,就相當(dāng)于發(fā)布。 什么是MVVM MVVM——Model-View-ViewModle的縮寫,MVC設(shè)計(jì)模式的改進(jìn)版。Model是我們應(yīng)用中的數(shù)據(jù)模型,View是我們的UI層,通過ViewModle,可以把我們M...
摘要:模塊則負(fù)責(zé)維護(hù),以及各個(gè)模塊間的調(diào)度思考題了解了的實(shí)現(xiàn)機(jī)制,你能否自己動(dòng)手也試著用百來行代碼實(shí)現(xiàn)一個(gè)庫呢好了本教程第一部分設(shè)計(jì)篇就寫到這里,具體請移步下一篇教學(xué)向行代碼教你實(shí)現(xiàn)一個(gè)低配版的庫代碼篇我會(huì)用給出一版實(shí)現(xiàn)。 適讀人群 本文適合對MVVM有一定了解(如有主流框架ng,vue等使用經(jīng)驗(yàn)配合本文服用則效果更佳),雖然會(huì)用這類框架,但是對框架底層核心實(shí)現(xiàn)又不太清楚,或者能說出個(gè)所以然...
摘要:當(dāng)我們的視圖和數(shù)據(jù)任何一方發(fā)生變化的時(shí)候,我們希望能夠通知對方也更新,這就是所謂的數(shù)據(jù)雙向綁定。返回值返回傳入函數(shù)的對象,即第一個(gè)參數(shù)該方法重點(diǎn)是描述,對象里目前存在的屬性描述符有兩種主要形式數(shù)據(jù)描述符和存取描述符。 前言 談起當(dāng)前前端最熱門的 js 框架,必少不了 Vue、React、Angular,對于大多數(shù)人來說,我們更多的是在使用框架,對于框架解決痛點(diǎn)背后使用的基本原理往往關(guān)注...
摘要:前言非正經(jīng)入門是相對正經(jīng)入門而言的。不過不要緊,正式學(xué)習(xí)仍需回到正經(jīng)入門的方式。快速入門建議先學(xué)會(huì)用拼文寫文檔注冊一個(gè)賬號,把庫到自己名下,然后用這個(gè)庫寫自己的博客,參見這份介紹。會(huì)用拼文寫文章,相當(dāng)于開發(fā)已入門三分之一了。 本系列博文從 Shadow Widget 作者的視角,解釋該框架的設(shè)計(jì)要點(diǎn),既作為用戶手冊的補(bǔ)充,也從更本質(zhì)角度幫助大家理解 Shadow Widget 為什么這...
閱讀 805·2023-04-25 15:13
閱讀 1425·2021-11-22 12:03
閱讀 844·2021-11-19 09:40
閱讀 1929·2021-11-17 09:38
閱讀 1739·2021-11-08 13:18
閱讀 675·2021-09-02 15:15
閱讀 1791·2019-08-30 15:54
閱讀 2661·2019-08-30 11:12