zoukankan      html  css  js  c++  java
  • 移动开发框架剖析(二) Hammer专业的手势控制

    浏览器底层并没有给元素提供类似,单击,双击,滑动,拖动这些直接可以用的控制接口,一切的手势动作都只能通过模拟出来。移动端浏览器唯一给我们提供的就只是mousedown -> mousemove -> mouseup三种最基本的事件接口。那么我们只能通过这些简单的接口模拟出复杂的手势出来。

    常规的做法流程:

    1.给元素上绑定三个事件,mousedown ,mousemove,mouseup

    2.在交互的时候,用户只触发mousedown,mouseup没有触发mousemove,就可以单算是一次点击的动作, 这里可以是 单击,双击与长按,具体可以通过间隔的时间判断

    3.如果mousemove触发了,自然就是滑动与拖动了

    当然手势还要涉及到多点操作缩放与旋转的处理,就之后在讨论。


    先抛开流程,我们要知道设计一个手势库需要考虑的问题,至少有2点:

    1.运行的平台

    2.用户的手势

    那么我们可以总结市面上的终端设备有那么三种:

    1 手机/pad移动端

    2 pc类

    3 还有种带触摸屏的电脑一类

    用户的手势行为大体分:

    单击tap , 双击doubletap,平移pan,滑动swipe,长按press,缩放pinch,旋转rotate


    从设计的角度来讲,有着不同的兼容与选择问题,却又有着一些相同的共性与处理我们要如何去组织结构?

    当然依旧是OOP设计了,抽出父类,实现继承,引入策略模式

    我们看看Hammer在结构上是如何实现这类设计的

    常规来说手势的处理,要分为初始化与执行期。初始化的时候构建所有相关的参与与方法

    hammer源码里面分几大块:

    1. Hammer类,一个简单的工厂方法,用来创建一个管理和初始化默认的识别器。Hammer.defaults配置一些基本的选项

    包括针对每种识别器的配置与元素CSS属性的设置

    2. Manager类,整个库的管理类。内部初始化了input输入对象,所有手势对象,元素css设置对象touchAction

    3. InputHandler类,事件回调的具体加工类,用来生成包装后的事件对象与派发事件到每一个识别器

    4. TouchAction类,设置元素的touchAction属性

    5. Input类,事件处理类。用来处理绑定与销毁,事件句柄的回调。每一个输入类都需要继承

    6. Recognizer类,所有识别器需要继承的基类

    以上就是整个库的类块了,当然5与6都是属于基类继承的,在代码运行的时候就自动构建完毕了


    关于继承inherit方法

    hammer用的是传统的类似继承

    function inherit(child, base, properties) {
        var baseP = base.prototype,
            childP;
    
        childP = child.prototype = Object.create(baseP);
        childP.constructor = child;
        childP._super = baseP;
    
        if (properties) {
            extend(childP, properties);
        }
    }

    只继承了原型的方法,因为原型都是共享的,如果放置属性可以被任何一个继承的子类所有修改,所以属性的继承需要用call方法

    继承的子类有一个私有属性 _super指向父类,同时还能额外的扩展方法

    inherit(MouseInput, Input, {
         handler: function MEhandler(ev){
        }
    }

    子类MouseInput继承父类Input类的所有原型方法,并扩展了handler方法


    输入设备初始化继承:就是通过什么设备触发动作(PC,手机,ipad等等)

    输入设备hammer分为

    MouseInput,PointerEventInput,SingleTouchInput,TouchInput,TouchMouseInput

    我们看看最简单的桌面PC的鼠标输入处理MouseInput,其余的结构基本类似。

    function MouseInput() {
        this.evEl = MOUSE_ELEMENT_EVENTS;
        this.evWin = MOUSE_WINDOW_EVENTS;
        //用来禁止TouchMouse事件
        this.allow = true; // used by Input.TouchMouse to disable mouse events
        //鼠标按下的状态
        this.pressed = false; // mousedown state
        Input.apply(this, arguments);
    }
    
    inherit(MouseInput, Input, {
         handler: function MEhandler(ev){
           ..//////////////
        }
    }

    MouseInput初始化了几个必要的判断属性,然后就只handler方法, 此外还集成了Input输入类

    比如我们调用

    new MouseInput(callback)的时候,通过Input.apply(this, arguments)去初始化了基类input类,然后基类内部的init绑定了事件,并且把事件的回调,

    this.domHandler指向了外部的callback回调,其实也就是handler方法了

    addEventListeners(this.element, this.evEl, this.domHandler);

    另一个基类就是Recognizer

    因为我们把用户的行为分为单击tap , 双击doubletap,平移pan,滑动swipe,长按press,缩放pinch,旋转rotate,那么类似相同点我们也必须抽象成一个基类

    Recognizer比如复杂,留在执行期的时候讲解。


    Hammer 使用:

    var mc = new Hammer(el);

    那么内部的构建

    function Hammer(element, options) {
        options = options || {};
        //配置手势识别器参数
        options.recognizers = ifUndefined(options.recognizers, Hammer.defaults.preset);
        return new Manager(element, options);
    }

    可见最终是Manager构建的对象实例了

    Manager内部,通过createInputInstance创建一个输入环境的实例对象,创建一个输入环境的实例对象

    this.input = createInputInstance(this);

    createInputInstance的作用主要是用来选择当然的平台,不同的平台会调用不同的手势输入处理,这里就有策略选择了的处理了

    function createInputInstance(manager) {
        var Type;
        var inputClass = manager.options.inputClass;
    
        if (inputClass) {
            Type = inputClass;
        } else if (SUPPORT_POINTER_EVENTS) {
            Type = PointerEventInput;
        } else if (SUPPORT_ONLY_TOUCH) {
            Type = TouchInput; //移动手机端
        } else if (!SUPPORT_TOUCH) {
            Type = MouseInput; //桌面
        } else {
            Type = TouchMouseInput;
        }
    }

    如果是桌面PC端,我们就会走MouseInput

    return new MouseInput(manager, inputHandler);

    这样把具体的通过Input类绑定的回调放到MouseInput的handler处理了,最终的回调会进入总处理inputHandler类

    inputHandler类就会遍历所有的手势识别器把输入的input传入

    manager.recognize(input);

    每一个识别器各自处理其行为了,当然这里面倒是如何触发,手势识别器如何判断是那种手势,就放一章了。

    官方:http://hammerjs.github.io/

    我的:https://github.com/JsAaron/hammer-js

  • 相关阅读:
    SQL SERVER将指定表中的指定字段按照(,)逗号分隔
    关于百度 UEditor的使用
    关于jquery的 $("form").serialize()和 new FormData表单序列化
    mvc5 + ef6 + autofac搭建项目(repository+uow)(二)
    (转载)[FFmpeg]使用ffmpeg从各种视频文件中直接截取视频图片
    sql查看数据库表使用情况
    EF FluentAPI映射一对多 关系时候报错
    (转载)Javascript 进阶 作用域 作用域链
    (转载)loadrunner简单使用——HTTP,WebService,Socket压力测试脚本编写
    [moka学习笔记]yii2.0 rules的用法(收集,不定期更新)
  • 原文地址:https://www.cnblogs.com/aaronjs/p/4029304.html
Copyright © 2011-2022 走看看