[关闭]
@hotjp 2017-04-08T10:53:07.000000Z 字数 3245 阅读 1300

如何快速解析一个库(插件)

培训


因hammer.js现有源码都是es6格式,编译后视图复杂,源码讲解前需要介绍es6语法,遂转向介绍touch.js

本文意在梳理整套代码实现思路,如有不足或忽略处,望斧正

touch.js源码地址

  1. 'use strict';

es5严格模式

  1. // line:3
  2. (function(root, factory) {
  3. if (typeof define === 'function' && (define.amd || define.cmd)) {
  4. define(factory); //Register as a module.
  5. } else {
  6. root.touch = factory();
  7. }
  8. }(this, function() {
  9. // 库源码
  10. }));

一个立即执行函数,标准的amd、cmd双支持模块化封装

this 指向window, factory 指向库本身,当没有任何模块化引擎( define 函数不存在)时,在 window.touch 中执行 factory 来生产如下对象。

  1. // line:969
  2. var exports = {};
  3. exports.on = exports.bind = exports.live = _on;
  4. exports.off = exports.unbind = exports.die = _off;
  5. exports.config = config;
  6. exports.trigger = _dispatch;
  7. return exports;
  8. <div class="md-section-divider"></div>

以上内容可以全部从之前的几次文档中找到影子 IIFE立即执行函数--一个复杂点的例子JavaScript面向对象编程--工厂模式


对于代码的理解有两种相辅相成的方法,顺向结构理解。

顺向

即按照函数的执行顺序,依照流程执行,理解发生的事件

大部分类库会依照unix的命名格式用init作为整个函数执行的开始,这属于未约定但俗成的风格。

init(为英语:initialization的简写)是 Unix 和 类Unix 系统中用来产生其它所有进程的程序

so,我们去寻找init函数所在位置

  1. //line:955
  2. //init gesture
  3. function init() {
  4. var mouseEvents = 'mouseup mousedown mousemove mouseout',
  5. touchEvents = 'touchstart touchmove touchend touchcancel';
  6. var bindingEvents = utils.hasTouch ? touchEvents : mouseEvents;
  7. bindingEvents.split(" ").forEach(function(evt) {
  8. document.addEventListener(evt, handlerOriginEvent, false);
  9. });
  10. }
  11. init();
  12. <div class="md-section-divider"></div>

可以简单的发现初始化的时候用到了以下函数或表达式

  1. // line:20
  2. utils.hasTouch = ('ontouchstart' in window);
  3. // line:716
  4. var handlerOriginEvent = function(ev) {
  5. var el = ev.target;
  6. switch (ev.type) {
  7. case 'touchstart':
  8. case 'mousedown':
  9. __rotation_single_start = [];
  10. __touchStart = true;
  11. if (!pos.start || pos.start.length < 2) {
  12. pos.start = utils.getPosOfEvent(ev);
  13. }
  14. if (utils.getFingers(ev) >= 2) {
  15. __initial_angle = parseInt(utils.getAngle180(pos.start[0], pos.start[1]), 10);
  16. }
  17. startTime = Date.now();
  18. startEvent = ev;
  19. __offset = {};
  20. var box = el.getBoundingClientRect();
  21. var docEl = document.documentElement;
  22. __offset = {
  23. top: box.top + (window.pageYOffset || docEl.scrollTop) - (docEl.clientTop || 0),
  24. left: box.left + (window.pageXOffset || docEl.scrollLeft) - (docEl.clientLeft || 0)
  25. };
  26. gestures.hold(ev);
  27. break;
  28. case 'touchmove':
  29. case 'mousemove':
  30. if (!__touchStart || !pos.start) return;
  31. pos.move = utils.getPosOfEvent(ev);
  32. if (utils.getFingers(ev) >= 2) {
  33. gestures.pinch(ev);
  34. } else if (__rotation_single_finger) {
  35. gestures.rotateSingleFinger(ev);
  36. } else {
  37. gestures.swipe(ev);
  38. }
  39. break;
  40. case 'touchend':
  41. case 'touchcancel':
  42. case 'mouseup':
  43. case 'mouseout':
  44. if (!__touchStart) return;
  45. endEvent = ev;
  46. if (startPinch) {
  47. gestures.pinch(ev);
  48. } else if (__rotation_single_finger) {
  49. gestures.rotateSingleFinger(ev);
  50. } else if (startSwiping) {
  51. gestures.swipe(ev);
  52. } else {
  53. gestures.tap(ev);
  54. }
  55. utils.reset();
  56. __initial_angle = 0;
  57. __rotation = 0;
  58. if (ev.touches && ev.touches.length === 1) {
  59. __touchStart = true;
  60. __rotation_single_finger = true;
  61. }
  62. break;
  63. }
  64. };

看完handlerOriginEvent就基本可以理解整个库的实现思路。

余下的内容就是需要花时间去看的各种类型判断,for循环和if判断,不多加赘述


结构

结构理解的模式往往不单独存在于对库的分析中,一般和顺向理解混用,掌握后,可以方便的快速理解框架内容和api

本例使用jetbrains提供的structure插件快速查看结构,大家最爱的可视化

image_1bd5l6g8jv9riikcii1bpug89.png-72.1kB

在结构视图中可以清晰看到整个文件的函数结构

image_1bd5l7t8vp06mtr3s41odoqim.png-26.9kB

不要问我左边的图标啥意思,看这个就知道了,不过我还截了图,你们爱我不?

image_1bd5m8nnt8l5ee3128t1n34bvm1g.png-33.1kB

用google翻译了一下,这次你们爱我了不?

image_1bd5m0vni18p6r3k1skn4p1144a13.png-29.5kB

关于λ的解释有点奇葩,所以我截了下英文,应该是 映射函数
啥,问我这个玩意怎么读? 来看我嘴型~~ 兰布达

通常来说,从结构面板里看到的是你需要知道的东西,需要理解的东西,实现思路,但是代码里的书写风格,是现阶段大家需要学习的东西,判断的处理,函数的运用。

问题

如何写一个支持模块化的封装?
怎样使用工厂模式?
为什么不根据想要的事件类型拆成8大18大函数处理,而是统一监听特定事件?
为什么用swith语句不用if语句?

还有文中故意没有提到的问题:
tap事件如何达到比click事件监听更快?
多手指的判断是怎么做出来的?
如何构建一个自定义事件?

请与会各位在下次交流前将以上问题的回答发送到我的邮箱 jiangqi@jerei.com

Attention!

请根据自己的能力结合今天交流的内容进行问题回答,将做为我对各位学习能力的评估。
因各种理由未能及时发送邮件的同志,hiehiehie~

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注