@hotjp
2017-04-08T10:53:07.000000Z
字数 3245
阅读 1300
培训
因hammer.js现有源码都是es6格式,编译后视图复杂,源码讲解前需要介绍es6语法,遂转向介绍touch.js
本文意在梳理整套代码实现思路,如有不足或忽略处,望斧正
touch.js源码地址
'use strict';
es5严格模式
// line:3
(function(root, factory) {
if (typeof define === 'function' && (define.amd || define.cmd)) {
define(factory); //Register as a module.
} else {
root.touch = factory();
}
}(this, function() {
// 库源码
}));
一个立即执行函数,标准的amd、cmd双支持模块化封装
this
指向window, factory
指向库本身,当没有任何模块化引擎( define
函数不存在)时,在 window.touch
中执行 factory
来生产如下对象。
// line:969
var exports = {};
exports.on = exports.bind = exports.live = _on;
exports.off = exports.unbind = exports.die = _off;
exports.config = config;
exports.trigger = _dispatch;
return exports;
<div class="md-section-divider"></div>
以上内容可以全部从之前的几次文档中找到影子 IIFE立即执行函数--一个复杂点的例子,JavaScript面向对象编程--工厂模式
对于代码的理解有两种相辅相成的方法,顺向
和结构
理解。
即按照函数的执行顺序,依照流程执行,理解发生的事件
大部分类库会依照unix的命名格式用init作为整个函数执行的开始,这属于未约定但俗成的风格。
init(为英语:initialization的简写)是 Unix 和 类Unix 系统中用来产生其它所有进程的程序
so,我们去寻找init
函数所在位置
//line:955
//init gesture
function init() {
var mouseEvents = 'mouseup mousedown mousemove mouseout',
touchEvents = 'touchstart touchmove touchend touchcancel';
var bindingEvents = utils.hasTouch ? touchEvents : mouseEvents;
bindingEvents.split(" ").forEach(function(evt) {
document.addEventListener(evt, handlerOriginEvent, false);
});
}
init();
<div class="md-section-divider"></div>
可以简单的发现初始化的时候用到了以下函数或表达式
// line:20
utils.hasTouch = ('ontouchstart' in window);
// line:716
var handlerOriginEvent = function(ev) {
var el = ev.target;
switch (ev.type) {
case 'touchstart':
case 'mousedown':
__rotation_single_start = [];
__touchStart = true;
if (!pos.start || pos.start.length < 2) {
pos.start = utils.getPosOfEvent(ev);
}
if (utils.getFingers(ev) >= 2) {
__initial_angle = parseInt(utils.getAngle180(pos.start[0], pos.start[1]), 10);
}
startTime = Date.now();
startEvent = ev;
__offset = {};
var box = el.getBoundingClientRect();
var docEl = document.documentElement;
__offset = {
top: box.top + (window.pageYOffset || docEl.scrollTop) - (docEl.clientTop || 0),
left: box.left + (window.pageXOffset || docEl.scrollLeft) - (docEl.clientLeft || 0)
};
gestures.hold(ev);
break;
case 'touchmove':
case 'mousemove':
if (!__touchStart || !pos.start) return;
pos.move = utils.getPosOfEvent(ev);
if (utils.getFingers(ev) >= 2) {
gestures.pinch(ev);
} else if (__rotation_single_finger) {
gestures.rotateSingleFinger(ev);
} else {
gestures.swipe(ev);
}
break;
case 'touchend':
case 'touchcancel':
case 'mouseup':
case 'mouseout':
if (!__touchStart) return;
endEvent = ev;
if (startPinch) {
gestures.pinch(ev);
} else if (__rotation_single_finger) {
gestures.rotateSingleFinger(ev);
} else if (startSwiping) {
gestures.swipe(ev);
} else {
gestures.tap(ev);
}
utils.reset();
__initial_angle = 0;
__rotation = 0;
if (ev.touches && ev.touches.length === 1) {
__touchStart = true;
__rotation_single_finger = true;
}
break;
}
};
看完handlerOriginEvent
就基本可以理解整个库的实现思路。
mouseEvents
,touchEvents
余下的内容就是需要花时间去看的各种类型判断,for循环和if判断,不多加赘述
结构理解的模式往往不单独存在于对库的分析中,一般和顺向理解混用,掌握后,可以方便的快速理解框架内容和api
本例使用jetbrains提供的structure
插件快速查看结构,大家最爱的可视化
在结构视图中可以清晰看到整个文件的函数结构
不要问我左边的图标啥意思,看这个就知道了,不过我还截了图,你们爱我不?
用google翻译了一下,这次你们爱我了不?
关于λ
的解释有点奇葩,所以我截了下英文,应该是 映射函数
啥,问我这个玩意怎么读? 来看我嘴型~~ 兰布达
通常来说,从结构面板里看到的是你需要知道的东西,需要理解的东西,实现思路,但是代码里的书写风格,是现阶段大家需要学习的东西,判断的处理,函数的运用。
如何写一个支持模块化的封装?
怎样使用工厂模式?
为什么不根据想要的事件类型拆成8大18大函数处理,而是统一监听特定事件?
为什么用swith语句不用if语句?
还有文中故意没有提到的问题:
tap事件如何达到比click事件监听更快?
多手指的判断是怎么做出来的?
如何构建一个自定义事件?
请与会各位在下次交流前将以上问题的回答发送到我的邮箱 jiangqi@jerei.com
请根据自己的能力结合今天交流的内容进行问题回答,将做为我对各位学习能力的评估。
因各种理由未能及时发送邮件的同志,hiehiehie~