接上文:一套代碼小程序&Web&Native運行的探索05——snabbdomhtml
對應Git代碼地址請見:https://github.com/yexiaochai/wxdemo/tree/master/mvvmnode
https://github.com/fastCreator/MVVM(極度參考,十分感謝該做者,直接看Vue會比較吃力的,可是看完這個做者的代碼便會輕易不少,惋惜這個做者沒有對應博客說明,否則就爽了)github
https://www.tangshuang.net/3756.html小程序
https://www.cnblogs.com/kidney/p/8018226.htmlapp
http://www.cnblogs.com/kidney/p/6052935.html框架
https://github.com/livoras/blog/issues/13dom
經過以前的學習,咱們斷斷續續的瞭解到了一套MVVM框架須要瞭解的精華(我以爲的精華):mvvm
① 模板解析,由模板生成框架element函數
② 生成渲染函數,由element生成render匿名函數,這裏便涉及到了指令的解析,render函數執行後生成了最終Vnode須要的數據字典,這裏完成了HTML->Vnode的所有工做
③ 使用snabbdom進行頁面渲染,後續數據更新調用發佈訂閱系統更新數據
而MVVM系統還有個比較關鍵的點是組件系統,通常認爲MVVM的量大特色實際上是響應式數據更新(Vnode相關),而後就是組件體系,這二者須要完成的工做都是讓咱們更搞笑的開發代碼,一個爲了解決紛亂的dom操做,一個爲了解決負責的業務邏輯結構,因此咱們今天便來學習組件體系相關邏輯
其實組件體系的實例化事實上跟new MVVM是一致的,只不過須要一點特殊處理,這裏咱們看其渲染時候的變化:
1 if (typeof tag == 'string') { 2 let Ctor = resolveAsset(this.$options, 'components', tag) 3 if (Ctor) { 4 return this._createComponent(Ctor, data, children, tag) 5 } 6 }
這裏對tag作了判斷,若是是字符串,而且咱們參數裏面傳遞了components參數,這裏便會拿出來執行createComponent邏輯:
1 //建立組件 2 //子組件option,屬性,子元素,tag 3 _createComponent(Ctor, data, children, sel) { 4 Ctor.data = mergeOptions(Ctor.data); 5 let componentVm; 6 let Factory = this.constructor 7 let parentData = this.$data 8 data.hook.insert = (vnode) => { 9 //... 10 } 11 Ctor._vnode = new VNode(sel,null,data, [], undefined, createElement(sel)); 12 return Ctor._vnode 13 }
這裏建立vnode的時候沒有作什麼特殊處理,因此咱們的會造成這樣的dom結構:
<my-component></my-component> <div m-for="(val, key, index) in arr">索引 1 :葉小釵</div> <div m-for="(val, key, index) in arr">索引 2 :素還真</div> <div m-for="(val, key, index) in arr">索引 3 :一頁書</div>
可是這裏有一個hook,在my-component做爲dom插入的時候回被調用:
1 _createComponent(Ctor, data, children, sel) { 2 Ctor.data = mergeOptions(Ctor.data); 3 let componentVm; 4 let Factory = this.constructor 5 let parentData = this.$data 6 data.hook.insert = (vnode) => { 7 Ctor.data = Ctor.data || {}; 8 var el =createElement('sel') 9 vnode.elm.append(el) 10 Ctor.el = el; 11 componentVm = new Factory(Ctor); 12 vnode.key = componentVm.uid; 13 componentVm._isComponent = true 14 componentVm.$parent = this; 15 (this.$children || (this.$children = [])).push(componentVm); 16 //寫在調用父組件值 17 for (let key in data.attrs) { 18 if (Ctor.data[key]) { 19 warn(`data:${key},已存在`); 20 continue; 21 } 22 } 23 } 24 Ctor._vnode = new VNode(sel,null,data, [], undefined, createElement(sel)); 25 return Ctor._vnode 26 }
這裏先建立了一個空標籤(sel)直接插入my-component中,而後執行與以前同樣的實例化流程:
componentVm = new Factory(Ctor);
這個會在patch後將實際的dom節點更新上去:
this.$el = patch(this.$el, vnode); //$el如今爲sel標籤(dom標籤)
這個就是snabbdom hook所幹的工做,能夠看到組件系統這裏有這些特色:
① 組件是一個獨立的mvvm實例,經過parent能夠找到其父親mvvm實例,可能跟實例,也多是另外一個組件
② 跟實例能夠根據$children參數找到其下面全部的組件
③ 組件與跟實例經過data作交流,原則不容許在組件內部改變屬性值,須要使用事件進行通訊,事件通訊就是在組件中的點擊事件不作具體的工做,而是釋放$emit(),這種東西讓跟實例調用,最終仍是以setData的方式改變基本數據,從而引起組件同步更新
因此只要把以前的內容搞懂了,組件一塊會比較輕鬆,咱們以前沒涉及到屬性,這裏咱們來試試數據傳遞:
html = ` <div ontap="onclick"> <my-component name="{{name}}"></my-component> <div m-for="(val, key, index) in arr">索引 {{key + 1}} :{{val}}</div> </div> ` let vm = new MVVM({ el: '#app', template: html, components: { 'my-component': { props: ['name'], template: '<div>{{name}}-children component!</div>' } }, data: { name: '葉小釵', age: 30, arr: [ '葉小釵', '素還真', '一頁書' ] }, methods: { onclick: function(e) { this.setData({ name: '素還真', age: this.age + 1 }); } } })
具體代碼各位看這裏吧:https://github.com/yexiaochai/wxdemo/tree/master/mvvm
通過簡單的學習,咱們大概瞭解了組件的流程,接下來咱們作下階段的整理,把以前學的東西連起來