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