摘要:模塊則負(fù)責(zé)維護(hù),以及各個模塊間的調(diào)度思考題了解了的實(shí)現(xiàn)機(jī)制,你能否自己動手也試著用百來行代碼實(shí)現(xiàn)一個庫呢好了本教程第一部分設(shè)計(jì)篇就寫到這里,具體請移步下一篇教學(xué)向行代碼教你實(shí)現(xiàn)一個低配版的庫代碼篇我會用給出一版實(shí)現(xiàn)。
適讀人群
本文適合對MVVM有一定了解(如有主流框架ng,vue等使用經(jīng)驗(yàn)配合本文服用則效果更佳),雖然會用這類框架,但是對框架底層核心實(shí)現(xiàn)又不太清楚,或者能說出個所以然,但是讓他自己動手寫又沒有頭緒的碼友。如果還沒聽說過MVVM,不妨先收藏著。。。
先給低配版的庫起一個響亮的名字,以便于開展教學(xué),入鄉(xiāng)隨俗我們就叫ta -- SegmentFault.js 吧 (以下簡稱sf.js)
設(shè)置在DOM Element上的自定義屬性前綴統(tǒng)一以 sf- 開頭 (如 )
為什么是低配版?1. 沒有sf-repeat 2. 不支持select,checkbox,radio等控件的雙向綁定 3. 沒有sf-if 4. 很多都沒有
由于是教學(xué)向,力圖用最簡短易讀的代碼來實(shí)現(xiàn)MVVM最主要最基本的功能,故砍掉了部分實(shí)現(xiàn)。
先看演示圖,圖中就是使用sf.js寫得DEMO
100多行的低配版不能要求太多,如果看不上低配版的庫,請關(guān)閉本教程。
首先明白一個概念,什么是雙向綁定?在說雙向綁定之前,我們先說說單向顯示。
單向顯示 說白了就是view動態(tài)地顯示變量。比如在ng或其它一些主流框架里類似這種寫法
//scope.message= "segmentfault";segmentfault
為什么說是單向呢,因?yàn)槎际?viewModel上某個變量(message) -> view (h3)的一個過程,viewModel上的變量被view所呈現(xiàn)。
再來看看 逆向修改
前面說了單向是viewMode->view的過程,那逆向就是 viewModel <- view的過程,換句話說就是viewModel被view修改的過程。例如angular中
一旦用戶在input控件中輸入值,便會實(shí)時(shí)地改變viewModel中message這個變量的值。這是一個view -> viewModel 的過程。
所謂的雙向綁定就是一個 viewMode ->(顯示) view ->(修改)viewModel 的過程。
雙向綁定 = 單向顯示 + 逆向修改
注意: 單向顯示可能發(fā)生在所有的類型DOM節(jié)點(diǎn)上,而逆向修改只可能發(fā)生在INPUT,SELECT,TEXTAREA等交互型控件上。
如果整明白什么是雙向綁定了,我們就來談?wù)勗O(shè)計(jì)思路,沒有整明白的同學(xué)請?jiān)匍喿x一遍.
單向顯示的設(shè)計(jì)思路(viewModel -> view)先看看API的設(shè)計(jì)
要實(shí)現(xiàn)這個功能,我們的sf庫應(yīng)該需要哪幾步操作呢?(先自己想想,獨(dú)立思考下)
1. 注冊ViewModel,我們的庫需要知道哪些object是viewModel 2. 掃描整個DOM Tree找到有哪些DOM節(jié)點(diǎn)上被配置了sf-xxxx這個attribute 3. 紀(jì)錄這些被單向綁定的DOM節(jié)點(diǎn)和viewModel之間的映射關(guān)系 4. 使用DOM API, element.innerText = vm.prop, element.value = vm.prop, element.xxxx = vm.prop 來顯示數(shù)據(jù)思考題1
Q:如果我們要單向綁定不是innerText,value 而是作為樣式的class,style呢?
A:沒錯,使用sf-class="vm.myClass" sf-style="vm.myStyle"就好了,其它原生屬性也以此類推
"sf-" + native attribute is good!
主流的一些mvvm框架上一般這么設(shè)計(jì)API,還是拿angular舉例子
這里我個人并不認(rèn)同這種xx-model的命名方式來作為雙向綁定的一種標(biāo)識,比如angular的ng-model,或Vue的v-model,撇開前綴不說,這個model很讓人困惑,我們知道input控件是本身就有value這個native的屬性的,這個屬性就是代表著input輸入和輸出的值,如果要給一個input進(jìn)行雙向綁定我們應(yīng)該很自然而然地使用一個 *-value就可以了,完全沒有必要弄出一個新的attribute叫做*-model的,從而增加學(xué)習(xí)成本。
所以,我們就設(shè)計(jì)一個叫做sf-value的attribute來做API
拍腦袋想想,view要改變數(shù)據(jù)只可能發(fā)生在可以和用戶交互的一些html控件上,比如input家族(text, radio, checkbox), select, textarea上。 像h1~hn家族,這輩子是沒有機(jī)會的。
要實(shí)現(xiàn)view改寫viewModel,我們的庫應(yīng)該需要哪幾步操作呢?(也先自己想想,千萬不要丟掉獨(dú)立思考能力)
1.掃描整個DOM Tree,找到哪些INPUT,SELECT,TEXTAREA節(jié)點(diǎn)上被配置了sf-value這個attribute 2.紀(jì)錄這些被雙向綁定的DOM節(jié)點(diǎn)和viewModel之間的映射關(guān)系 3.sf.js庫自動給這個寫DOM加上onchange或者oninput的事件監(jiān)聽 4.一旦監(jiān)聽到change/input事件,立即獲取這個DOM的value值,把這個element.value賦給與之綁定的viewModel的變量上。思考題2
Q:那么問題來了,vm.message被input修改了,誰去通知其它同樣綁定了vm.message的view呢?
A:請看下一段
臟檢查大法 這三個字想必大家已經(jīng)如雷貫耳,我2年多前出去面試的時(shí)候被問及最多的就是angular的臟檢查,什么是臟檢查?angular臟檢查的時(shí)機(jī)是什么?
臟檢查的原理就是,拷貝一份copy_viewModel在內(nèi)存中,一旦有用戶點(diǎn)擊,輸入操作,或ajax請求,setInterval,setTimeout等這些可能導(dǎo)致viewModel發(fā)生改變的行為,框架都會把copy_viewModel和最新的viewModel進(jìn)行深度比較,一旦發(fā)現(xiàn)有屬性(如vm.message)發(fā)生變化,則重新渲染與message綁定的DOM節(jié)點(diǎn)。
這也是為什么,一旦你沒有使用ng自帶的$http,$interval,$timeout,ng-click這些angular自己封裝的API去操作viewModel,angular都不會自動去同步view,因?yàn)橐呀?jīng)超出他的管轄范圍了,你必須手動調(diào)用apply函數(shù)去強(qiáng)制執(zhí)行一次臟檢查,以同步view。
setter大法
聽說VUE是使用的這種同步機(jī)制,其核心原理就是使用Object.defineProperty(obj, prop, descriptor)(不了解defineProperty的請戳)這個API,在setter中加點(diǎn)料,一旦有任何地方執(zhí)行 vm.message = "new value"語句,則setter都會被調(diào)用,由setter去觸發(fā)重新渲染view的邏輯。
相較這兩種同步機(jī)制,似乎setter更加輕便,性能更好。所以本文使用了setter的方式來實(shí)現(xiàn)同步機(jī)制(關(guān)鍵是實(shí)現(xiàn)setter機(jī)制使用的代碼較少)。
設(shè)計(jì)思路給setter加點(diǎn)料
http://jsbin.com/gosigoh/edit...
所以歸納來說一個MVVM庫主要由3塊組成
MVVM庫 = 單向顯示 + 逆向修改 + 同步機(jī)制
下圖為SegmentFault.js的實(shí)現(xiàn)機(jī)制
其中Renderer負(fù)責(zé)單向顯示和逆向修改,Watcher負(fù)責(zé)監(jiān)視viewModel為同步機(jī)制的核心模塊,
Scanner負(fù)責(zé)sf.js初始化時(shí)掃描DOM Tree生成view和viewModel的映射關(guān)系。
SegmentFault模塊則負(fù)責(zé)維護(hù)view-viewModel Map,以及各個模塊間的調(diào)度
Q:了解了MVVM的實(shí)現(xiàn)機(jī)制,你能否自己動手也試著用百來行代碼實(shí)現(xiàn)一個MVVM庫呢?
好了!本教程第一部分設(shè)計(jì)篇就寫到這里,具體coding請移步(下一篇 【教學(xué)向】150行代碼教你實(shí)現(xiàn)一個低配版的MVVM庫(2)- 代碼篇)
我會用Typescript給出一版實(shí)現(xiàn)。
2年前寫了我受夠了angular的笨重,學(xué)習(xí)曲線陡峭等缺點(diǎn),自己一怒之下寫下一個輕量的MVVM庫,給她起名叫【Ukulele.js】(跟我一起念『尤克里里.杰愛死』,當(dāng)然本文不是這個庫的安利文,請安心服用),一開始寫這個庫出于好玩,后來也加入了越來越多的功能,諸如web component的支持,我漸漸發(fā)現(xiàn),其實(shí)要寫一個MVVM庫也并不是很難,難的是你有沒有決心敲下第一行代碼。后來我把她和【精通angularjs】一起寫在里簡歷里,然后就去找工作了。面試的時(shí)候被問及最多的問題就是:"說說MVVM的實(shí)現(xiàn)機(jī)制"。
我今天寫下此文,1是希望有機(jī)會看到這篇文章的碼友能真正掌握MVVM的核心機(jī)制,2是鼓勵下大家能靜下心來,自己動手寫寫庫,寫寫框架,有些你現(xiàn)在覺得蠻高大上的東西,你仔細(xì)一分析,動動腦,真的沒有那么高大上,普通的碼農(nóng)也能自己實(shí)現(xiàn)
相關(guān)閱讀【教學(xué)向】150行代碼教你實(shí)現(xiàn)一個低配版的MVVM庫(1)- 原理篇
【教學(xué)向】150行代碼教你實(shí)現(xiàn)一個低配版的MVVM庫(2)- 代碼篇
【教學(xué)向】再加150行代碼教你實(shí)現(xiàn)一個低配版的web component庫(1) —設(shè)計(jì)篇
【教學(xué)向】再加150行代碼教你實(shí)現(xiàn)一個低配版的web component庫(2) —原理篇
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/87348.html
摘要:為的內(nèi)置一個方法,用法和原生的事件機(jī)制一毛一樣。 前言 上兩篇Mvvm教程的熱度超出我的預(yù)期,很多碼友留言表揚(yáng)同時(shí)希望我繼續(xù)出下一篇教程,當(dāng)時(shí)我也半開玩笑說只要點(diǎn)贊超10就兌現(xiàn)承諾,沒想到還真破了10,所以就有了今天的文章。 準(zhǔn)備工作 熟讀 【教學(xué)向】150行代碼教你實(shí)現(xiàn)一個低配版的MVVM庫(1)- 原理篇【教學(xué)向】150行代碼教你實(shí)現(xiàn)一個低配版的MVVM庫(2)- 代碼篇 本篇是在...
摘要:也放出地址,上面有完整工程以及在線演示地址相關(guān)閱讀教學(xué)向行代碼教你實(shí)現(xiàn)一個低配版的庫原理篇教學(xué)向行代碼教你實(shí)現(xiàn)一個低配版的庫代碼篇教學(xué)向再加行代碼教你實(shí)現(xiàn)一個低配版的庫設(shè)計(jì)篇教學(xué)向再加行代碼教你實(shí)現(xiàn)一個低配版的庫原理篇 書接上一篇: 150行代碼教你實(shí)現(xiàn)一個低配版的MVVM庫(1)- 原理篇 寫在前面 為了便于分模塊,和閱讀,我使用了Typescript來進(jìn)行coding,總行數(shù)是正好...
摘要:前端日報(bào)精選瀏覽器兼容性問題解決方案配置指南全新的模塊化框架,知乎專欄現(xiàn)學(xué)現(xiàn)賣中文教學(xué)向再加行代碼教你實(shí)現(xiàn)一個低配版的庫原理篇我把最美的青春都獻(xiàn)給了代碼技術(shù)周刊開啟瀏覽器全屏模式如何進(jìn)行的操作掘金內(nèi)存分配與垃圾回收寫一 2017-08-29 前端日報(bào) 精選 瀏覽器兼容性問題解決方案AlloyTeam ESLint 配置指南全新的redux模塊化框架,redux-arena - 知乎專欄...
摘要:前言月份開始出沒社區(qū),現(xiàn)在差不多月了,按照工作的說法,就是差不多過了三個月的試用期,準(zhǔn)備轉(zhuǎn)正了一般來說,差不多到了轉(zhuǎn)正的時(shí)候,會進(jìn)行總結(jié)或者分享會議那么今天我就把看過的一些學(xué)習(xí)資源主要是博客,博文推薦分享給大家。 1.前言 6月份開始出沒社區(qū),現(xiàn)在差不多9月了,按照工作的說法,就是差不多過了三個月的試用期,準(zhǔn)備轉(zhuǎn)正了!一般來說,差不多到了轉(zhuǎn)正的時(shí)候,會進(jìn)行總結(jié)或者分享會議!那么今天我就...
閱讀 2843·2021-11-22 13:54
閱讀 2767·2021-10-14 09:42
閱讀 4174·2021-09-28 09:47
閱讀 2245·2021-09-03 10:28
閱讀 1272·2021-07-26 23:38
閱讀 2622·2019-08-30 15:54
閱讀 2705·2019-08-29 16:35
閱讀 1502·2019-08-29 15:42