一步一步写一个极简es6版本backbone

284 阅读3分钟
原文链接: zhuanlan.zhihu.com

我们首先需要考虑的两个问题。

  1. 一个mv*框架如backbone有哪些部分组成。(Model,View,Controller)
  2. 他们之间通过何种方式串联起来,相互通信。(发布订阅者模式)

发布订阅者模式

监听事件变动,触发回调。

首先我们创建一个Event对象,里面用几个函数on(type, listener) ,off(type, listener),emit(type, args)分别表示监听某种事件、取消监听和触发三个操作。

在on(type, listener)里面,我们监听某个事件,然后把它放入一个数组。需要触发的时候,循环执行里面的函数即可如emit.删除同理。

Model,View和Event关系。

三者关系如上。Model和View分别继承Event. Model和View通过组合的方式关联在一起。

Model如何监听触发数据变动

Es6里面引入了getter/setter方法,当某个对象的属性被查询或者赋值时被调用。而我们可以用Object.defineProperty(obj, prop, descriptor)为我们Model的值添加setter/gettter方法。

当set函数被调用的时候,触发事件。

JS事件处理。

backbone里面是的事件是专门用events这个对象定义的,如下。

    events: {
        'click .toggle': 'toggle',
        'dblclick label': 'edit',
        'click .destroy': 'onClickDestroy',
        'keydown .edit': 'onKeyPressEdit',
        'keypress .edit': 'onKeyPressEdit',
    },

三者分别是事件、选择器和事件处理函数。

  1. 如何将定义的事件与dom结合起来,
  2. dom更新之后如何再次绑定。

这里用的是代理模式。用一个根节点el代理所有的事情,在事件触发的判断是不是对应的选择器。Dom里面有个matches可以判断是否。如果匹配我们就调用eventhandlers.

var result = element.matches(selectorString); 

View的组成成分

  1. 模板,这里用ES6字符串模板(backbone里面用了underscore的模板)。
  2. el,用来代理事件和模板插入。
  3. model,数据。
  4. children,用来处理多个view组合的情况。
export default class View extends Event {
    constructor(props) {
        super(props);

        this.el = props.el || this.getWrap();
        this.model = props.model || {};
        this.children = [];
        this.delegateEvents();
    }

模板-> Dom转换

这里非常简单的用innerHtml来做转化。

this.el.innerHTML='<div></div>'

至此,一个es6 backbone的主要要素已经完全准备好,我们只要根据以上内容,就可以写出完整的框架,源码地址:[es6webpack](xff1874/es6backbone)

存在的问题

  1. 模板处理太弱。这里只用了简单的ES6字符串。无法处理复杂的逻辑,比如if,else逻辑。backbone用了underscore的模板。
  2. 事件处理和模板的绑定关系太弱。要明确写出选择器事件处理函数等,不能像vue和react模板是事件和模板绑定在一起。
  3. 性能问题。每次view更新,就要重新销毁创建children。性能损耗很大。
  4. 自定义指令。如v-bind,ng-model="foo"。 好处是某些地方用指令确实方便,比如双向绑定,功能更强大,但是坏处是每一个框架都有自己的一套指令,学习成本高。
  5. view与view的关系。现在是用命令式,只能new出来。不能随意组合。这个还是模板问题
<div><customcomponent/></div>

本文代码主要参考了[rasti](8tentaculos/rasti)