Skip to content
This repository has been archived by the owner on Nov 12, 2024. It is now read-only.

view的事件设计细节 #33

Open
xinglie opened this issue Feb 19, 2017 · 0 comments
Open

view的事件设计细节 #33

xinglie opened this issue Feb 19, 2017 · 0 comments

Comments

@xinglie
Copy link
Member

xinglie commented Feb 19, 2017

在说事件设计细节之前,先讲一下view的设计,便于理解事件的设计

view的设计

view的设计原则上要求view尽可能的独立,尤其是view之间应该相互独立。像iframe标签一样,每个内容都是一个独立的单元。

view的分类

在实际使用中,可以简单把view归为两大类。

一类是完成界面功能,比如下拉框、弹出框、业务中的header,footer等,这些view拥有自己的html及可能有的css。不但有功能,还有相应的界面。

再一类就是增强界面功能的,比如已经存在了列表界面,列表项带checkbox及一个全选checkbox。这时候我们实现一个view,用于联动checkbox。当然,这个功能可以使用mixin实现,也可以用view来实现,通常这类view只有功能,没有界面

view的示例代码

我们对前述的view做一个示例,更直观的来看下具体情况
我们需要三个view:入口(index) 列表 (list) 联动checkbox (linkage)

接下来我们只展示入口index的html部分

<!-- index.html -->
<div>
    <ul mx-view="app/views/linkage">
        <li><input type="checkbox" data-checkbox-type="all" />全选</li>
        <li><input type="checkbox" data-checkbox-type="one"/>1</li>
        <li><input type="checkbox" data-checkbox-type="one"/>2</li>
        <li><input type="checkbox" data-checkbox-type="one"/>3</li>
        <li><input type="checkbox" data-checkbox-type="one"/>4</li>
    </ul>
    <div mx-view="app/views/list">
        loading...
    </div>
</div>

该示例里面,ul标签上的app/views/linkage加载后会控制li里面的checkbox联动。
下面的div标签上的app/views/list加载后,会把真实的列表内容填充进来。

view的事件处理

对上述示例,我们添加一些事件来讲述具体的细节。

<!--  index.html  -->
<div>
    <ul mx-view="app/views/linkage">
        <li mx-click="clickLi()"><input mx-click="clickAll()" type="checkbox" data-checkbox-type="all" />全选</li>
        <li><input type="checkbox" data-checkbox-type="one"/>1</li>
        <li><input type="checkbox" data-checkbox-type="one"/>2</li>
        <li><input type="checkbox" data-checkbox-type="one"/>3</li>
        <li><input type="checkbox" data-checkbox-type="one"/>4</li>
    </ul>
    <div mx-view="app/views/list">
        <div>正在加载数据,如果长时间不显示,请<a href="javascript:;" mx-click="retry()">点击这里重试</a></div>
    </div>
</div>

此时对应的index.js可能如下

//index.js
var Magix = require('magix');
module.exports = Magix.View.extend({
    tmpl: '@index.html'
    render: function() {

    },
    'clickLi<click>': function(e) {
        console.log('li ', e);
    },
    'clickAll<click>': function(e) {
        console.log('all ', e);
    },
    'retry<click>': function(e) {
        console.log('retry ', e);
    }
});

我们从html上结构上来看,这些事件clickLi、clickAll及retry都是在其它view所属的范围内的,比如clickLi和clickAll离的最近的view是app/views/linkage,retry离的最近的view是app/views/list。所以当click事件发生时,magix该如何处理它们?

magix之前的版本是找最近的view,然后把事件交与最近的view来处理,但是显然从这个例子来看,这个做法是不妥的。理想的做法是:谁创建的界面,谁负责事件处理。

所以这个问题高效的解决方案是使用magix配套的magix-combine工具来打包view。另外magix仍然内置了动态查找,以应对不使用工具时也能正确处理。

所以到目前为止,这种在html写mx-eventType的方式可以方便的解决,然而棘手的是另外一个事件绑定

view支持选择器绑定事件

通常带界面的我们可以很方便的通过在html里添加mx-eventType属性来标记事件的处理方法,这也是我们推荐的做法,而对于不带界面的view,如前述的linkage来联动checkbox的,我们就没办法使用这样的方案来绑定事件了。

所以这时候我们可以调用类库的事件绑定来自己处理,如

//linkage.js
var Magix = require('magix');
var $ = require('jquery');
module.exports = Magix.View.extend({
    init: function() {
        var me = this;
        $('#' + me.id + ' input[data-checkbox-type=all]').on('change', function() {
            me.processAll();
        });
        $('#' + me.id + ' input[data-checkbox-type=one]').on('change', function() {
            me.processOne();
        });
    },
    processAll: function() {

    },
    processOne: function() {

    }
});

这种方式也是可以的,但是显然开发者要考虑事件绑定,还需要考虑事件解绑,同时还要考虑动态添加的checkbox,还要考虑只处理当前view范围内的checkbox。所以需要开发者关注的事情较多,magix综合这些问题,推出了以下的方案

//linkage.js
var Magix = require('magix');
var $ = require('jquery');
module.exports = Magix.View.extend({
    processAll: function() {

    },
    processOne: function() {

    },
    '$input[data-checkbox-type=all]<change>': function(e) {
        this.processAll();
    },
    '$input[data-checkbox-type=one]<change>': function(e) {
        this.processOne();
    }
});

以$开头的表示接下来是一个选择器,开发者不需要考虑绑定、解绑、动态添加、移除、只选择当前范围内的元素等问题,magix会自动帮你搞定。

支持了选择器绑定事件后,接下来就有一个比较现实的问题:

view可以自由嵌套,选择器很可能会选中子view中的节点元素。(其实css也有这样的问题,当然这是另外一个话题了。)

所以到这里我们就有必要讨论一下如果用选择器来绑定事件的话,如果子view也有能被选择器选择到的节点,该如何处理?

magix的最终结论是和在mx-eventType中的事件行为保持一致,这是其中一点,另一点是前述的view设计,view本身就要求尽可能的独立,所以自己的事情自己办,所有的view中的事件只在当前范围内生效。

那么magix该如何处理选中子view中的节点元素?这块已从代码上解决,关键点见下述内容

选择器事件绑定细节

  1. 所有view有没有渲染结束magix是知道的,详见view的源码endUpdate方法
  2. view有没有界面也是知道的,我们约定有界面的一定有tmpl属性
  3. 所有事件绑定在magix中都是统一处理的
  4. 当选择器绑定的事件发生时,向上查找最近的vframe,如果经过已经渲染过的,且带界面的vframe,则停止查找,事件也不再派发,只有找到 绑定选择器事件时view与查找到的view相同,才派发事件。

更多细节则需要从代码上查看了

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant