阿富

web前端

导航

【事件】touch事件整合(DOM2级、单点触控)

'use strict';

/*
//接口:添加事件
.addEvent(element, {
    start: base.noop, //开始
    move: base.noop, //移动
    end: base.noop, //结束
    click: base.noop, //结束---点击
    long: base.noop, //结束---长按
    mainAxis: null, //主滑动轴(null | 'x' | 'y')
    stopPropagation: false, //事件传播
    namespace: '' //事件命名空间
});
e.data.changeX //x变化值
e.data.changeY //y变化值
e.data.changeXAbs //x变化绝对值
e.data.changeYAbs //y变化绝对值
e.data.initialAxis //null | 'x' | 'y'
e.data.endAction //null | 'left' | 'right' | 'top' | 'down' | 'click' | 'long'
e.data.endSpeed //速度

//接口:解除事件
.removeEvents(element);
.removeEvents(element, 'namespace');

//接口:触发事件(仅用于'click'及'long')
.trigger(element, 'click', [event]);
.trigger(element, 'click.namespace', [event]);
*/

var base = new(require('./base.js'))();



var moduleName = 'touch',
    $P = Module.prototype;

function Module() {
    if (!(this instanceof Module)) {
        return new Module();
    }
    this.name = moduleName;
    base.setReadOnly(this, 'name'); //设置只读
}
module.exports = Module;



var stamp = '_touchData' + Date.now();



//接口:添加事件
$P.addEvent = (function() {
    var defaults = {
        start: base.noop,
        move: base.noop,
        end: base.noop,
        click: base.noop,
        long: base.noop,
        mainAxis: null,
        stopPropagation: false,
        namespace: ''
    };
    var setOptions = function(options) {
        var _o = options;
        if (typeof _o.mainAxis === 'string') {
            _o.mainAxis = _o.mainAxis.trim();
        }
        if (typeof _o.stopPropagation !== 'boolean') {
            _o.stopPropagation = defaults.stopPropagation;
        }
        _o.namespace = _o.namespace.trim();
    };
    var recordEvent = function(element, functions, namespace) { //记录事件
        functions.namespace = namespace;
        if (Array.isArray(element[stamp])) {
            element[stamp].push(functions);
        } else {
            element[stamp] = [functions];
        }
    };
    var speedValve = 64;
    return function(element, options) {
        if (!(element instanceof HTMLElement)) {
            return;
        }
        options = base.extend({}, defaults, options);
        setOptions(options);
        var started = false;
        var startD = {},
            data = {};
        var touchstart = function(e) {
            if (options.stopPropagation) {
                e.stopPropagation();
            } else {
                e.stopPropagation = base.noop;
            }
            if (e.targetTouches.length === 1) {
                started = true;
                startD = {};
                startD.x = e.targetTouches[0].clientX;
                startD.y = e.targetTouches[0].clientY;
                startD.t = e.timeStamp;
                data = {};
                data.changeX = 0;
                data.changeY = 0;
                data.changeXAbs = 0;
                data.changeYAbs = 0;
                data.initialAxis = null;
                data.endAction = null;
                data.endSpeed = 0;
                e.data = base.extend({}, data);
                options.start.apply(this, arguments);
            }
        };
        var touchmove = function(e) {
            if (options.stopPropagation) {
                e.stopPropagation();
            } else {
                e.stopPropagation = base.noop;
            }
            if (e.targetTouches.length === 1 && started) {
                data.changeX = e.targetTouches[0].clientX - startD.x;
                data.changeY = e.targetTouches[0].clientY - startD.y;
                data.changeXAbs = Math.abs(data.changeX);
                data.changeYAbs = Math.abs(data.changeY);
                if (!data.initialAxis) {
                    if (data.changeXAbs > 6 || data.changeYAbs > 6) { //6px内锁定initialAxis值
                        if (options.mainAxis === 'y') {
                            data.initialAxis = data.changeXAbs / 2 > data.changeYAbs ? 'x' : 'y';
                        } else if (options.mainAxis === 'x') {
                            data.initialAxis = data.changeYAbs / 2 > data.changeXAbs ? 'y' : 'x';
                        } else {
                            data.initialAxis = data.changeXAbs > data.changeYAbs ? 'x' : 'y';
                        }
                        startD.x = e.targetTouches[0].clientX;
                        startD.y = e.targetTouches[0].clientY;
                    }
                }
                e.data = base.extend({}, data);
                options.move.apply(this, arguments);
            }
        };
        var touchend = function(e) {
            if (options.stopPropagation) {
                e.stopPropagation();
            } else {
                e.stopPropagation = base.noop;
            }
            if (e.targetTouches.length === 0 && started) {
                started = false;
                var totalTime = e.timeStamp - startD.t;
                data.endSpeed = (Math.sqrt(Math.pow(data.changeXAbs, 2) + Math.pow(data.changeYAbs, 2))) / totalTime * 300;
                if (data.initialAxis === 'x') {
                    if (data.endSpeed > speedValve) {
                        if (data.changeX < 0) {
                            data.endAction = 'left';
                        } else {
                            data.endAction = 'right';
                        }
                    }
                } else if (data.initialAxis === 'y') {
                    if (data.endSpeed > speedValve) {
                        if (data.changeY < 0) {
                            data.endAction = 'top';
                        } else {
                            data.endAction = 'down';
                        }
                    }
                } else if (totalTime < 300) {
                    data.endAction = 'click';
                } else {
                    data.endAction = 'long';
                }
                e.data = base.extend({}, data);
                options.end.apply(this, arguments);
                if (data.endAction === 'click' || data.endAction === 'long') {
                    options[data.endAction].apply(this, arguments);
                }
                startD = {};
                data = {};
            }
        };
        element.addEventListener('touchstart', touchstart);
        element.addEventListener('touchmove', touchmove);
        element.addEventListener('touchend', touchend);
        recordEvent(element, [touchstart, touchmove, touchend], options.namespace); //记录事件
        touchend.long = options.long; //用于事件触发器
        touchend.click = options.click; //同上
        touchend.propagate = !options.stopPropagation; //同上
    };
})();



//接口:解除事件
$P.removeEvents = (function() {
    var removeEvents = function(element, functions) {
        element.removeEventListener('touchstart', functions[0]);
        element.removeEventListener('touchmove', functions[1]);
        element.removeEventListener('touchend', functions[2]);
    };
    return function(element, namespace) {
        if (!(element instanceof HTMLElement)) {
            return;
        }
        var touchData = element[stamp];
        if (Array.isArray(touchData)) {
            namespace = namespace === undefined ? '' : namespace.trim();
            for (var i = 0; i < touchData.length; i++) {
                if (namespace) {
                    if (touchData[i].namespace === namespace) {
                        removeEvents(element, touchData[i]);
                        touchData.splice(i, 1);
                        i--;
                    }
                } else {
                    removeEvents(element, touchData[i]);
                    touchData.splice(i, 1);
                    i--;
                }
            }
            if (touchData.length === 0) {
                delete element[stamp];
            }
        }
    };
})();



//接口:触发事件(仅用于'click'及'long')
$P.trigger = function(element, param, event) {
    if (!(element instanceof HTMLElement)) {
        return;
    }
    param = param.trim().split('.');
    var type = param[0],
        namespace = param[1];
    if (type === 'click' || type === 'long') {
        event = base.extend({
            target: element
        }, event);
        var propagate = true;
        var fireEvent = function(_el) {
            var touchData = _el[stamp];
            if (Array.isArray(touchData)) {
                for (var i = 0; i < touchData.length; i++) {
                    if (namespace) {
                        if (touchData[i].namespace === namespace) {
                            touchData[i][2][type].call(_el, event);
                            if (touchData[i][2].propagate === false) {
                                propagate = false;
                            }
                        }
                    } else {
                        touchData[i][2][type].call(_el, event);
                        if (touchData[i][2].propagate === false) {
                            propagate = false;
                        }
                    }
                }
            }
            if (propagate && _el.parentElement) { //递归冒泡
                fireEvent(_el.parentElement);
            }
        };
        fireEvent(element);
    }
};



// //测试
// document.addEventListener('DOMContentLoaded', function() {

//     var touch = new Module();
//     var e_html = document.documentElement;

//     touch.addEvent(e_html, {
//         start: function(e) {
//             window.console.log('start:', JSON.stringify(e.data), '\n\n');
//         },
//         move: function(e) {
//             window.console.log('move:', JSON.stringify(e.data));
//         },
//         end: function(e) {
//             window.console.log('\n\nend:', JSON.stringify(e.data));
//         },
//         click: function(e) {
//             window.console.log('end(click):', e);
//         },
//         long: function(e) {
//             window.console.log('end(long):', e);
//         },
//         mainAxis: 'y',
//         stopPropagation: true,
//         namespace: 'namespace'
//     });
//     touch.addEvent(e_html, {
//         click: function(e) {
//             window.console.log(e.target);
//         }
//     });

//     touch.removeEvents(e_html);
//     touch.removeEvents(e_html, 'namespace');

//     touch.trigger(e_html, 'click');
//     touch.trigger(e_html, 'click.namespace');
//     touch.trigger(e_html, 'long');
//     touch.trigger(e_html, 'long.namespace');

// });

 

posted on 2016-07-14 22:08  阿富  阅读(352)  评论(0)    收藏  举报