摘要:嘗試使用新特性,自己來實(shí)現(xiàn)一個(gè)及的各種特性。我們可以利用這個(gè)特性來實(shí)現(xiàn)對數(shù)據(jù)的監(jiān)聽結(jié)果簡單的操作我們已經(jīng)可以對簡單的數(shù)據(jù)操作進(jìn)行監(jiān)聽雖然還有各種問題,接下來,我們只要在監(jiān)聽到后進(jìn)行數(shù)據(jù)操作即可。
最簡單的watcher嘗試使用es6新特性,自己來實(shí)現(xiàn)一個(gè)mvvm及vue的各種特性。
相關(guān)代碼放在github,會持續(xù)更新,歡迎賞個(gè)star。
本篇文章為系列文章的第一篇,會比較容易理解,后續(xù)會持續(xù)更新后面的記錄。
文章首發(fā)于本人博客
從開始接觸Vue開始,我們便對它的“數(shù)據(jù)響應(yīng)”贊嘆不絕,那么我們首先,來實(shí)現(xiàn)一個(gè)最簡單的watcher,來監(jiān)聽數(shù)據(jù),以進(jìn)行對應(yīng)的操作,類似后續(xù)會涉及的dom操作等。
Proxy我們都知道,Vue使用Object.defineProperty來進(jìn)行數(shù)據(jù)監(jiān)聽,監(jiān)聽obj的get和set方法。在ES6中,Proxy可以攔截某些操作的默認(rèn)行為,也就是對目標(biāo)對象的訪問進(jìn)行攔截,過濾和改寫。我們可以利用這個(gè)特性來實(shí)現(xiàn)對數(shù)據(jù)的監(jiān)聽:
const watcher = (obj, fn) => { return new Proxy(obj, { get (target, prop, receiver) { return Reflect.get(target, prop, receiver) }, set (target, prop, value) { const oldValue = Reflect.get(target, prop, receiver) const result = Reflect.set(target, prop, value) fn(value, oldValue) return result } }) }
結(jié)果:
let obj = watcher({ a: 1 }, (val, oldVal) => { console.log("old =>> ", oldVal) console.log("new =>> ", val) }) obj.a = 2 // old =>> , 1 // new =>> , 2簡單的Dom操作
我們已經(jīng)可以對簡單的數(shù)據(jù)操作進(jìn)行監(jiān)聽(雖然還有各種問題),接下來,我們只要在監(jiān)聽到dom后進(jìn)行數(shù)據(jù)操作即可。解析模板什么的我們就先不做了,我們可以繼續(xù)利用Proxy實(shí)現(xiàn)一個(gè)dom輔助函數(shù):
const dom = new Proxy({}, { get (target, tagName) { return (attrs = {}, ...childrens) => { // 創(chuàng)建節(jié)點(diǎn) const elem = document.createElement(tagName) // 添加attribute attrs.forEach(attr => elem.addAttribute(attr, attrs[attr]) // 添加子元素 childrens.forEach(child => { const child = typeof child === "string" ? document.createTextNode(child) : child elem.appendChild(child) }) return elem } } })
也就是說,我們?yōu)閐om的各屬性進(jìn)行監(jiān)聽,當(dāng)訪問對應(yīng)的節(jié)點(diǎn)時(shí),我們創(chuàng)建并且為他添加各種屬性等:
dom.div( {class: "wrap"}, "helloworld", dom.a({ href: "https://www.360.cn" }, "welcome to 360") ) // 輸出拼接基礎(chǔ)框架helloworld welcome to 360
我們在這里給我們的這個(gè)小架子起名為"W",讓它可以真正的運(yùn)行起來。類似Vue的語法,我們需要在進(jìn)行實(shí)例化的時(shí)候,watch我們的data,并且更新dom。類似這樣:
const vm = new W({ el: "body", data () { return { msg: "hello world" } }, render () { return dom.div({ class: "wrap" }, dom.a({ href: "http://www.360.cn" }, this.msg) ) } })
因此,我們需要實(shí)現(xiàn)這樣一個(gè)類,來處理我們的參數(shù),并進(jìn)行實(shí)例的初始化,監(jiān)聽,以及渲染控制等。
export default class W { constructor (config) {} /** * observe data */ _initData () {} /** * 渲染節(jié)點(diǎn) */ _renderDom () {} }初始化數(shù)據(jù)
首先,我們進(jìn)行數(shù)據(jù)初始化,將數(shù)據(jù)置為observable,在對其修改的時(shí)候進(jìn)行監(jiān)聽:
import watcher from "./data.js" class W { constructor (config) { const { data = () => {} } = config this._config = config this._initData(data) return this._vm } } _initData (data) { this._vm = watcher(Object.assign({}, this, data()), this._renderDom.bind(this)) }
在這里我們需要注意兩點(diǎn):
我們的data參數(shù)為一個(gè)function
這個(gè)原因在vue官方文檔已經(jīng)說過,當(dāng)我們直接使用對象的時(shí)候,不同的實(shí)例間會共享同一個(gè)對象,導(dǎo)致出現(xiàn)對一個(gè)組件進(jìn)行修改,另一個(gè)組件也進(jìn)行修改的問題。具體可以查看data-必須是函數(shù)
我們返回的是this._vm而不是this
我們這里做了兩步操作,首先將this與data進(jìn)行合并,再將整個(gè)對象進(jìn)行監(jiān)聽,并賦值到_vm屬性上。
這樣,我們通過new W()初始化的實(shí)例,則可以訪問到我們的data屬性及方法,并且具有數(shù)據(jù)驅(qū)動(dòng)的特性了。
更新DOM我們已經(jīng)為watcher的回調(diào)添加了dom更新的事件,我們只要在這里執(zhí)行render函數(shù),并掛載到對應(yīng)的el上即可:
const { render, el } = this._config const targetEl = document.querySelector(el) const renderDom = render() targetEl.innerHTML = "" targetEl.appendChild(renderDom)綁定this
我們會發(fā)現(xiàn),我們在config的render函數(shù)中,使用了this.msg來訪問data的msg屬性,因此我們需要實(shí)現(xiàn)在各組件中,通過this可以訪問到本實(shí)例的特性。我猜你已經(jīng)想到了,我們可以使用bind,call和apply來實(shí)現(xiàn)它:
/** * 為所有的函數(shù)綁定this */ bindVM () { const { _config } = this for(let key of Object.keys(_config)) { const val = _config[key] if (typeof(val) === "function") { _config[key] = val.bind(this._vm) } } }測試
簡單的架子拼接完成,我們來進(jìn)行測試下我們的成果,我們需要實(shí)現(xiàn)兩點(diǎn)功能:
可以按照我們的render函數(shù)正常掛載,并可訪問到data上的數(shù)據(jù)
通過對實(shí)例進(jìn)行修改,修改會自動(dòng)更新到節(jié)點(diǎn)上
代碼:
const vm = new W({ el: "body", data () { return { msg: "hello world" } }, render () { return dom.div({ class: "wrap" }, dom.a({ href: "http://www.360.cn" }, this.msg) ) } }) // 測試修改vm setInterval(_ => { vm.msg = "hello world =>>>" + new Date() }, 1000)
結(jié)果:
最基本的功能已經(jīng)實(shí)現(xiàn)啦!
結(jié)語本次我們只實(shí)現(xiàn)了最最最簡單的數(shù)據(jù)驅(qū)動(dòng)功能,后續(xù)還有很多需要進(jìn)行處理,我們也會對其一一進(jìn)行梳理和實(shí)現(xiàn),大家可以持續(xù)關(guān)注下,例如:
數(shù)組變動(dòng)監(jiān)聽
object深度監(jiān)聽
更新隊(duì)列
render過程中記錄僅相關(guān)的屬性
模板渲染
v-model
...等等
相關(guān)代碼放在github,會持續(xù)更新,歡迎賞個(gè)star。
敬請期待!
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/84306.html
摘要:嘗試使用新特性,自己來實(shí)現(xiàn)一個(gè)及的各種特性。我們可以利用這個(gè)特性來實(shí)現(xiàn)對數(shù)據(jù)的監(jiān)聽結(jié)果簡單的操作我們已經(jīng)可以對簡單的數(shù)據(jù)操作進(jìn)行監(jiān)聽雖然還有各種問題,接下來,我們只要在監(jiān)聽到后進(jìn)行數(shù)據(jù)操作即可。 嘗試使用es6新特性,自己來實(shí)現(xiàn)一個(gè)mvvm及vue的各種特性。相關(guān)代碼放在github,會持續(xù)更新,歡迎賞個(gè)star。本篇文章為系列文章的第一篇,會比較容易理解,后續(xù)會持續(xù)更新后面的記錄。文...
摘要:可以在該鉤子中進(jìn)一步地更改狀態(tài),不會觸發(fā)附加的重渲染過程。我工作中只用到,對和不怎么熟與的區(qū)別相同點(diǎn)都支持指令內(nèi)置指令和自定義指令都支持過濾器內(nèi)置過濾器和自定義過濾器都支持雙向數(shù)據(jù)綁定都不支持低端瀏覽器。 看看面試題,只是為了查漏補(bǔ)缺,看看自己那些方面還不懂。切記不要以為背了面試題,就萬事大吉了,最好是理解背后的原理,這樣面試的時(shí)候才能侃侃而談。不然,稍微有水平的面試官一看就能看出,是...
摘要:目前已經(jīng)在大大小小多個(gè)線上產(chǎn)品中使用了,也收集了一些有效的建議好了,該看下一個(gè)最簡單的組件長什么樣吧免費(fèi)領(lǐng)取驗(yàn)證碼內(nèi)容安全短信發(fā)送直播點(diǎn)播體驗(yàn)包及云服務(wù)器等套餐更多網(wǎng)易技術(shù)產(chǎn)品運(yùn)營經(jīng)驗(yàn)分享請?jiān)L問網(wǎng)易云社區(qū)。文章來源網(wǎng)易云社區(qū) 本文由作者鄭海波授權(quán)網(wǎng)易云社區(qū)發(fā)布。 此文摘自regularjs的指南, 目前指南正在全面更新, 把老文檔的【接口/語法部分】統(tǒng)一放到了獨(dú)立的 Reference...
摘要:前端的發(fā)展歷程什么是前端前端針對瀏覽器的開發(fā),代碼在瀏覽器運(yùn)行后端針對服務(wù)器的開發(fā),代碼在服務(wù)器運(yùn)行前端三劍客超文本標(biāo)記語言是構(gòu)成世界的基石。 前端的發(fā)展歷程 什么是前端 前端:針對瀏覽器的開發(fā),代碼在瀏覽器運(yùn)行 后端:針對服務(wù)器的開發(fā),代碼在服務(wù)器運(yùn)行 前端三劍客 HTML CSS JavaScript HTML HTML(超文本標(biāo)記語言——HyperText Markup ...
摘要:前端面試題總結(jié)持續(xù)更新中是哪個(gè)組件的屬性模塊的組件。都提供合理的鉤子函數(shù),可以讓開發(fā)者定制化地去處理需求。 前端面試題總結(jié)——VUE(持續(xù)更新中) 1.active-class是哪個(gè)組件的屬性? vue-router模塊的router-link組件。 2.嵌套路由怎么定義? 在 VueRouter 的參數(shù)中使用 children 配置,這樣就可以很好的實(shí)現(xiàn)路由嵌套。 //引入兩個(gè)組件 ...
閱讀 2284·2021-09-27 13:35
閱讀 571·2019-08-30 15:55
閱讀 823·2019-08-30 15:53
閱讀 569·2019-08-30 15:52
閱讀 2157·2019-08-30 12:59
閱讀 2284·2019-08-29 16:42
閱讀 1449·2019-08-26 18:26
閱讀 2482·2019-08-26 13:48