@hotjp
2017-04-08T02:53:07.000000Z
字数 3245
阅读 1494
培训
因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:969var 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 gesturefunction 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:20utils.hasTouch = ('ontouchstart' in window);// line:716var 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~