Omi框架学习之旅 - 插件机制之omi-finger 及原理说明

以前那篇我写的alloyfinger源码解读那篇帖子,就说过这是一个很好用的手势库,hammer能做的,他都能做到,

而且源码只有350来行代码,很容易看懂。

那么怎么把这么好的库作为omi库的一个插件呢,使dom,用起来更爽,更方便呢?

omi自己有个叫插件体系的功能,主要是赋予dom元素一些能力,并且可以和组件的实例产生关联。

这当然棒极了。那怎么实现的呢?

还是先看个demo,看看用起来爽不,爽的话,再看原理也不迟啊。

 

        OmiFinger.init();    // 初始化OmiFinger插件

        class App extends Omi.Component {
            constructor(data) {
                super(data);
            }

            style() {
                return  `
                    .touchArea{
                        background-color: green;
                        width: 200px;
                        min-height: 200px;
                        text-align: center;
                        color:white;
                        height:auto;
                    }
                 `;
            }

            tap(evt) {
                console.log(this.refs.div1);
                this.refs.ptext.innerHTML = 'tap';
            }

            longTap(evt) {
                console.log(evt);
                this.refs.ptext.innerHTML = 'longTap';
            }

            swipe(evt) {
                this.refs.ptext.innerHTML = evt.direction;
            }

            render() {
                return  `
                <div>
                    <div omi-finger class="touchArea" tap="tap" longTap="longTap" swipe="swipe" ref="div1">    <!--在这里写事件名即可-->
                        Tap or Swipe Me!
                        <p ref="ptext"></p>
                    </div>
                </div>
                `;
            }

        }

        var app = new App();
        Omi.render(app, 'body');

 

看下结果:

 

我热,就是这么简单,就把rotate  touchStart  multipointStart  multipointEnd  pinch  swipe  tap  doubleTap  longTap  singleTap  pressMove  touchMove  touchEnd  touchCancel这14个事件都能赋给dom去监听相应的实例函数。

的确很方便,很omi,一个类(哦,不,一个组件(大家都喜欢叫组件,我内心是拒绝的))管理一切啊。

 

demo的疑问和疑问的说明:

疑问一:

那omi是怎么做到的啊?

答: 其实omi的插件机制代码很少,少的可怜,只是作为Component原型上_execPlugins方法,当然少不了和omi挂钩了,Omi上有个plugins对象属性,里面专门放插件名及插件函数的。

      那就一步一步来吧。

      demo上的OmiFinger.init();其实就是把初始化了一个插件,放到omi.plugins上去了,仅此而已,没帮我们做别的。来看源码

     

    Omi.plugins = {};    // omi插件集合

    // 扩展插件的方法(其实是给了plugins这个对象)
    Omi.extendPlugin = function(name, handler) {
        Omi.plugins[name] = handler;
    };

 

再来看一下OmiFinger.init();方法是不是调用了Omi.extendPlugin方法

var OmiFinger = {};
    var noop = function(){ };

    var getHandler = function(name, dom, instance) {
        var value = dom.getAttribute(name);    // 从属性上获取对应的函数名
        if (value === null) {
            return noop;
        }else{
            return instance[value].bind(instance);    // 从类上找到对应的方法
        };
    };

    OmiFinger.init = function(){
        Omi.extendPlugin('omi-finger',function(dom, instance){
            if (!instance.alloyFingerInstances) instance.alloyFingerInstances = [];    // finger的实例都存到这里面
            var len = instance.alloyFingerInstances.length;
            var i = 0;
            for( ; i<len; i++){
                if(instance.alloyFingerInstances[i].dom === dom){    // 如果以前绑定过得, 就先销毁, 然后重新來过
                    instance.alloyFingerInstances[i].fg.destroy();
                    instance.alloyFingerInstances.splice(i,1);    // 并且剔除
                    break;
                };
            };
            var alloyFinger = new AlloyFinger(dom,{
                touchStart: getHandler('touchStart', dom, instance),
                touchMove: getHandler('touchMove', dom, instance),
                touchEnd: getHandler('touchEnd', dom, instance),
                touchCancel: getHandler('touchCancel', dom, instance),
                multipointStart: getHandler('multipointStart', dom, instance),
                multipointEnd: getHandler('multipointEnd', dom, instance),
                tap: getHandler('tap', dom, instance),
                doubleTap: getHandler('doubleTap', dom, instance),
                longTap: getHandler('longTap', dom, instance),
                singleTap: getHandler('singleTap', dom, instance),
                rotate: getHandler('rotate', dom, instance),
                pinch: getHandler('pinch', dom, instance),
                pressMove: getHandler('pressMove', dom, instance),
                swipe: getHandler('swipe', dom, instance)
            });
            instance.alloyFingerInstances.push({fg:alloyFinger,dom:dom});
        });
    }

    OmiFinger.destroy = function(){
        delete Omi.plugins['omi-finger'];
    };
    
    window.OmiFinger = OmiFinger;

这里我把代码都贴出来,因为比较简单。

Omi.plugins有了对象插件名和函数,那是怎么循环遍历的呢?

其实就在Component类的_render方法最后面,遍历的,也就是当html插入到指定容器后,再调用的。

那是怎么调用的呢?

    // 插件机制
    _execPlugins(){
        Object.keys(Omi.plugins).forEach(item => {    // 遍历omi的插件
            let nodes = Omi.$$('*['+item+']',this.node);    // 具有插件名属性的dom
            nodes.forEach(node => {
                if(node.hasAttribute(this._omi_scoped_attr) ) {    // 节点是否含有_omi_scoped_id属性
                    Omi.plugins[item](node, this);    // 调用插件init方法中第二个函数
                };
            });
            if(this.node.hasAttribute(item)) {    // 看一下根节点是否含有插件名属性,有的话也执行
                Omi.plugins[item](this.node, this);
            };
        });
    }

可以看到,会传2个参数,一个dom,一个实例.正是验证了官网的这句话。 Omi插件体系可以赋予dom元素一些能力,并且可以和组件的实例产生关联。

至此就这么说完了。

 

ps: 

     当然还有transform.js, touch.js也可以让dom玩的飞起,后续再写帖子吧。

posted @ 2017-03-30 11:20  Sorrow.X  阅读(558)  评论(0编辑  收藏  举报