一套代码小程序&Web&Native运行的探索06——组件系统

接上文:一套代码小程序&Web&Native运行的探索05——snabbdomhtml

对应Git代码地址请见:https://github.com/yexiaochai/wxdemo/tree/master/mvvmnode

参考:
git

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

通过简单的学习,咱们大概了解了组件的流程,接下来咱们作下阶段的整理,把以前学的东西连起来

相关文章
相关标签/搜索