'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');
// });