摘要:嘗試使用新特性,自己來實現一個及的各種特性。我們可以利用這個特性來實現對數據的監聽結果簡單的操作我們已經可以對簡單的數據操作進行監聽雖然還有各種問題,接下來,我們只要在監聽到后進行數據操作即可。
最簡單的watcher嘗試使用es6新特性,自己來實現一個mvvm及vue的各種特性。
相關代碼放在github,會持續更新,歡迎賞個star。
本篇文章為系列文章的第一篇,會比較容易理解,后續會持續更新后面的記錄。
文章首發于本人博客
從開始接觸Vue開始,我們便對它的“數據響應”贊嘆不絕,那么我們首先,來實現一個最簡單的watcher,來監聽數據,以進行對應的操作,類似后續會涉及的dom操作等。
Proxy我們都知道,Vue使用Object.defineProperty來進行數據監聽,監聽obj的get和set方法。在ES6中,Proxy可以攔截某些操作的默認行為,也就是對目標對象的訪問進行攔截,過濾和改寫。我們可以利用這個特性來實現對數據的監聽:
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 } }) }
結果:
let obj = watcher({ a: 1 }, (val, oldVal) => { console.log("old =>> ", oldVal) console.log("new =>> ", val) }) obj.a = 2 // old =>> , 1 // new =>> , 2簡單的Dom操作
我們已經可以對簡單的數據操作進行監聽(雖然還有各種問題),接下來,我們只要在監聽到dom后進行數據操作即可。解析模板什么的我們就先不做了,我們可以繼續利用Proxy實現一個dom輔助函數:
const dom = new Proxy({}, { get (target, tagName) { return (attrs = {}, ...childrens) => { // 創建節點 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 } } })
也就是說,我們為dom的各屬性進行監聽,當訪問對應的節點時,我們創建并且為他添加各種屬性等:
dom.div( {class: "wrap"}, "helloworld", dom.a({ href: "https://www.360.cn" }, "welcome to 360") ) // 輸出拼接基礎框架helloworld welcome to 360
我們在這里給我們的這個小架子起名為"W",讓它可以真正的運行起來。類似Vue的語法,我們需要在進行實例化的時候,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) ) } })
因此,我們需要實現這樣一個類,來處理我們的參數,并進行實例的初始化,監聽,以及渲染控制等。
export default class W { constructor (config) {} /** * observe data */ _initData () {} /** * 渲染節點 */ _renderDom () {} }初始化數據
首先,我們進行數據初始化,將數據置為observable,在對其修改的時候進行監聽:
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)) }
在這里我們需要注意兩點:
我們的data參數為一個function
這個原因在vue官方文檔已經說過,當我們直接使用對象的時候,不同的實例間會共享同一個對象,導致出現對一個組件進行修改,另一個組件也進行修改的問題。具體可以查看data-必須是函數
我們返回的是this._vm而不是this
我們這里做了兩步操作,首先將this與data進行合并,再將整個對象進行監聽,并賦值到_vm屬性上。
這樣,我們通過new W()初始化的實例,則可以訪問到我們的data屬性及方法,并且具有數據驅動的特性了。
更新DOM我們已經為watcher的回調添加了dom更新的事件,我們只要在這里執行render函數,并掛載到對應的el上即可:
const { render, el } = this._config const targetEl = document.querySelector(el) const renderDom = render() targetEl.innerHTML = "" targetEl.appendChild(renderDom)綁定this
我們會發現,我們在config的render函數中,使用了this.msg來訪問data的msg屬性,因此我們需要實現在各組件中,通過this可以訪問到本實例的特性。我猜你已經想到了,我們可以使用bind,call和apply來實現它:
/** * 為所有的函數綁定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) } } }測試
簡單的架子拼接完成,我們來進行測試下我們的成果,我們需要實現兩點功能:
可以按照我們的render函數正常掛載,并可訪問到data上的數據
通過對實例進行修改,修改會自動更新到節點上
代碼:
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)
結果:
最基本的功能已經實現啦!
結語本次我們只實現了最最最簡單的數據驅動功能,后續還有很多需要進行處理,我們也會對其一一進行梳理和實現,大家可以持續關注下,例如:
數組變動監聽
object深度監聽
更新隊列
render過程中記錄僅相關的屬性
模板渲染
v-model
...等等
相關代碼放在github,會持續更新,歡迎賞個star。
敬請期待!
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/51052.html
摘要:嘗試使用新特性,自己來實現一個及的各種特性。我們可以利用這個特性來實現對數據的監聽結果簡單的操作我們已經可以對簡單的數據操作進行監聽雖然還有各種問題,接下來,我們只要在監聽到后進行數據操作即可。 嘗試使用es6新特性,自己來實現一個mvvm及vue的各種特性。相關代碼放在github,會持續更新,歡迎賞個star。本篇文章為系列文章的第一篇,會比較容易理解,后續會持續更新后面的記錄。文...
摘要:可以在該鉤子中進一步地更改狀態,不會觸發附加的重渲染過程。我工作中只用到,對和不怎么熟與的區別相同點都支持指令內置指令和自定義指令都支持過濾器內置過濾器和自定義過濾器都支持雙向數據綁定都不支持低端瀏覽器。 看看面試題,只是為了查漏補缺,看看自己那些方面還不懂。切記不要以為背了面試題,就萬事大吉了,最好是理解背后的原理,這樣面試的時候才能侃侃而談。不然,稍微有水平的面試官一看就能看出,是...
摘要:目前已經在大大小小多個線上產品中使用了,也收集了一些有效的建議好了,該看下一個最簡單的組件長什么樣吧免費領取驗證碼內容安全短信發送直播點播體驗包及云服務器等套餐更多網易技術產品運營經驗分享請訪問網易云社區。文章來源網易云社區 本文由作者鄭海波授權網易云社區發布。 此文摘自regularjs的指南, 目前指南正在全面更新, 把老文檔的【接口/語法部分】統一放到了獨立的 Reference...
摘要:前端面試題總結持續更新中是哪個組件的屬性模塊的組件。都提供合理的鉤子函數,可以讓開發者定制化地去處理需求。 前端面試題總結——VUE(持續更新中) 1.active-class是哪個組件的屬性? vue-router模塊的router-link組件。 2.嵌套路由怎么定義? 在 VueRouter 的參數中使用 children 配置,這樣就可以很好的實現路由嵌套。 //引入兩個組件 ...
閱讀 2849·2021-11-22 11:56
閱讀 3553·2021-11-15 11:39
閱讀 898·2021-09-24 09:48
閱讀 759·2021-08-17 10:14
閱讀 1322·2019-08-30 15:55
閱讀 2753·2019-08-30 15:55
閱讀 1310·2019-08-30 15:44
閱讀 2775·2019-08-30 10:59