1. 程式人生 > >一套代碼小程序&Web&Native運行的探索06——組件系統

一套代碼小程序&Web&Native運行的探索06——組件系統

vnode sel 更新數據 com native scom define 現在 直接

接上文:一套代碼小程序&Web&Native運行的探索05——snabbdom

對應Git代碼地址請見:https://github.com/yexiaochai/wxdemo/tree/master/mvvm

參考:

https://github.com/fastCreator/MVVM(極度參考,十分感謝該作者,直接看Vue會比較吃力的,但是看完這個作者的代碼便會輕易很多,可惜這個作者沒有對應博客說明,不然就爽了)

https://www.tangshuang.net/3756.html

https://www.cnblogs.com/kidney/p/8018226.html

http://www.cnblogs.com/kidney/p/6052935.html

https://github.com/livoras/blog/issues/13

通過之前的學習,我們斷斷續續的了解到了一套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

經過簡單的學習,我們大概了解了組件的流程,接下來我們做下階段的整理,把之前學的東西連起來

一套代碼小程序&Web&Native運行的探索06——組件系統