博客已经停滞了一段时间了,目前一年是在跟js打交道,从最初的android到React-Native然后再到H5,也就短短的1年的时间,几乎明天都在学习,我tm都佩服我自己是怎么坚持下来的……^^,因为有android基础,所以RN上手相对容易一点,但是对于h5真的是从几乎0开始,一开始做东西的时候是灰常恐惧的,都不知道自己写出来的东西运行起来到底咋样,慢慢的遇到的坑多了,也就没什么感觉了(虽然现在依然很菜 ^^),哈哈,就当是心里安慰一下自己了,毕竟接下来的路还很长很长……

说了那么多p话,进入今天的主题哈,虽然iscroll已经出来了很久了,也已经在很多前端大牛身边耳濡目染了,所以对于我(一个刚准备入坑h5的人)来说,iscroll还是带着一层神秘面纱的,一直想着哪天能够好好地去读读她,刚好最近在写列表需求,发现自带的overflow:scroll在原生(ios/android)上运行的时候遇到很多坑,比如ios跟android的滚动效果不一样、内存消耗太大、适配太烂、扩展性太差等等.

先附上iscroll的文档跟github地址:
官方文档:http://iscrolljs.com/#scrollbars
github地址:https://github.com/cubiq/iscroll/

其实用法啥的官方文档已经写的很清楚了,我这边就不啰嗦了,小伙伴自己去看哈(虽然tm都是英文^_^,也还是要去看看的).

之前搞android的养成了一个毛病,就是喜欢边看源码然后结合文档去读别人的第三方库,你还别说,还是有点效果的!所以也建议小伙伴可以这样去读第三方库哈,没必须弄懂每一行代码,大概思路就可以了~

我们直接去github上面把源码clone下来:

可以看到,东西还是挺多的,包括iscroll的源码,然后各种demo,不得不说,作者平时还是比较闲的,哈哈哈~~~~

我们先看看最简单的用法:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0, minimum-scale=1.0, maximum-scale=1.0"><title>iScroll demo: simple</title><script type="text/javascript" src="../../build/iscroll.js"></script>
<script type="text/javascript" src="../demoUtils.js"></script>
<script type="text/javascript">var myScroll;function loaded () {myScroll = new IScroll('#wrapper', { mouseWheel: true,scrollbars: true,shrinkScrollbars: 'scale',snap: true});
}document.addEventListener('touchmove', function (e) { e.preventDefault(); }, isPassive() ? {capture: false,passive: false
} : false);</script><style type="text/css">
* {-webkit-box-sizing: border-box;-moz-box-sizing: border-box;box-sizing: border-box;
}html {-ms-touch-action: none;
}body,ul,li {padding: 0;margin: 0;border: 0;
}body {font-size: 12px;font-family: ubuntu, helvetica, arial;overflow: hidden; /* this is important to prevent the whole page to bounce */
}#header {position: absolute;z-index: 2;top: 0;left: 0;width: 100%;height: 45px;line-height: 45px;background: #CD235C;padding: 0;color: #eee;font-size: 20px;text-align: center;font-weight: bold;
}#footer {position: absolute;z-index: 2;bottom: 0;left: 0;width: 100%;height: 48px;background: #444;padding: 0;border-top: 1px solid #444;
}#wrapper {position: absolute;z-index: 1;top: 45px;bottom: 48px;left: 0;width: 100%;background: #ccc;overflow: hidden;
}#scroller {position: absolute;z-index: 1;-webkit-tap-highlight-color: rgba(0,0,0,0);width: 100%;-webkit-transform: translateZ(0);-moz-transform: translateZ(0);-ms-transform: translateZ(0);-o-transform: translateZ(0);transform: translateZ(0);-webkit-touch-callout: none;-webkit-user-select: text;-moz-user-select: text;-ms-user-select: text;user-select: text;-webkit-text-size-adjust: none;-moz-text-size-adjust: none;-ms-text-size-adjust: none;-o-text-size-adjust: none;text-size-adjust: none;
}#scroller ul {list-style: none;padding: 0;margin: 0;width: 100%;text-align: left;
}#scroller li {padding: 0 10px;height: 40px;line-height: 40px;border-bottom: 1px solid #ccc;border-top: 1px solid #fff;background-color: #fafafa;font-size: 10px;-webkit-text-size-adjust: none;-moz-text-size-adjust: none;-ms-text-size-adjust: none;-o-text-size-adjust: none;text-size-adjust: none;
}</style>
</head>
<body onload="loaded()">
<div id="header">iScroll</div><div id="wrapper"><div id="scroller"><ul><li>Pretty row 1</li><li>Pretty row 2</li><li>Pretty row 3</li><li>Pretty row 4</li><li>Pretty row 5</li><li>Pretty row 6</li><li>Pretty row 7</li><li>Pretty row 8</li><li>Pretty row 9</li><li>Pretty row 10</li><li>Pretty row 11</li><li>Pretty row 12</li><li>Pretty row 13</li><li>Pretty row 14</li><li>Pretty row 15</li><li>Pretty row 16</li><li>Pretty row 17</li><li>Pretty row 18</li><li>Pretty row 19</li><li>Pretty row 20</li><li>Pretty row 21</li><li>Pretty row 22</li><li>Pretty row 23</li><li>Pretty row 24</li><li>Pretty row 25</li><li>Pretty row 26</li><li>Pretty row 27</li><li>Pretty row 28</li><li>Pretty row 29</li><li>Pretty row 30</li><li>Pretty row 31</li><li>Pretty row 32</li><li>Pretty row 33</li><li>Pretty row 34</li><li>Pretty row 35</li><li>Pretty row 36</li><li>Pretty row 37</li><li>Pretty row 38</li><li>Pretty row 39</li><li>Pretty row 40</li><li>Pretty row 41</li><li>Pretty row 42</li><li>Pretty row 43</li><li>Pretty row 44</li><li>Pretty row 45</li><li>Pretty row 46</li><li>Pretty row 47</li><li>Pretty row 48</li><li>Pretty row 49</li><li>Pretty row 50</li></ul></div>
</div><div id="footer"></div></body>
</html>

用法很简单:

第一步:指定滑动的包裹元素,设置其高度、并且设置其overflow: hidden去除元素默认的滚动

#wrapper {position: absolute;z-index: 1;top: 45px;bottom: 48px;left: 0;width: 100%;background: #ccc;overflow: hidden;
}
<div id="wrapper">....</div>

第二步:设置内部滑动元素,也就是滑动的主体部分及其内容


<div id="wrapper"><div id="scroller"><ul><li>Pretty row 1</li><li>Pretty row 2</li>....<li>Pretty row 50</li></ul></div>
</div>

第三步:等dom加载完毕的时候创建iscroll对象,并绑定滑动包裹元素

var myScroll;function loaded () {myScroll = new IScroll('#wrapper');
}

好啦~ 简单的几步操作之后,我们就可以开心的玩起来了.

当我们创建一个iscroll对象的时候,我们去源码里看看它干了什么.

首先看iscroll的构造方法:

function IScroll (el, options) {this.wrapper = typeof el == 'string' ? document.querySelector(el) : el;this.scroller = this.wrapper.children[0];this.scrollerStyle = this.scroller.style;       // cache style for better performancethis.options = {resizeScrollbars: true,mouseWheelSpeed: 20,snapThreshold: 0.334,// INSERT POINT: OPTIONSdisablePointer : !utils.hasPointer,disableTouch : utils.hasPointer || !utils.hasTouch,disableMouse : utils.hasPointer || utils.hasTouch,startX: 0,startY: 0,scrollY: true,directionLockThreshold: 5,momentum: true,bounce: true,bounceTime: 600,bounceEasing: '',preventDefault: true,preventDefaultException: { tagName: /^(INPUT|TEXTAREA|BUTTON|SELECT)$/ },HWCompositing: true,useTransition: true,useTransform: true,bindToWrapper: typeof window.onmousedown === "undefined"};for ( var i in options ) {this.options[i] = options[i];}// Normalize optionsthis.translateZ = this.options.HWCompositing && utils.hasPerspective ? ' translateZ(0)' : '';this.options.useTransition = utils.hasTransition && this.options.useTransition;this.options.useTransform = utils.hasTransform && this.options.useTransform;this.options.eventPassthrough = this.options.eventPassthrough === true ? 'vertical' : this.options.eventPassthrough;this.options.preventDefault = !this.options.eventPassthrough && this.options.preventDefault;// If you want eventPassthrough I have to lock one of the axesthis.options.scrollY = this.options.eventPassthrough == 'vertical' ? false : this.options.scrollY;this.options.scrollX = this.options.eventPassthrough == 'horizontal' ? false : this.options.scrollX;// With eventPassthrough we also need lockDirection mechanismthis.options.freeScroll = this.options.freeScroll && !this.options.eventPassthrough;this.options.directionLockThreshold = this.options.eventPassthrough ? 0 : this.options.directionLockThreshold;this.options.bounceEasing = typeof this.options.bounceEasing == 'string' ? utils.ease[this.options.bounceEasing] || utils.ease.circular : this.options.bounceEasing;this.options.resizePolling = this.options.resizePolling === undefined ? 60 : this.options.resizePolling;if ( this.options.tap === true ) {this.options.tap = 'tap';}// https://github.com/cubiq/iscroll/issues/1029if (!this.options.useTransition && !this.options.useTransform) {if(!(/relative|absolute/i).test(this.scrollerStyle.position)) {this.scrollerStyle.position = "relative";}}if ( this.options.shrinkScrollbars == 'scale' ) {this.options.useTransition = false;}this.options.invertWheelDirection = this.options.invertWheelDirection ? -1 : 1;// INSERT POINT: NORMALIZATION// Some defaultsthis.x = 0;this.y = 0;this.directionX = 0;this.directionY = 0;this._events = {};// INSERT POINT: DEFAULTSthis._init();this.refresh();this.scrollTo(this.options.startX, this.options.startY);this.enable();
}

我们慢慢来看哈,首先是获取wrapper跟scroller元素:

this.wrapper = typeof el == 'string' ? document.querySelector(el) : el;this.scroller = this.wrapper.children[0];

然后就是初始化一些参数:

this.options = {resizeScrollbars: true, //是否重置scrollbar的大小mouseWheelSpeed: 20, //鼠标滑动的速度snapThreshold: 0.334, //翻页的距离值// INSERT POINT: OPTIONSdisablePointer : !utils.hasPointer,disableTouch : utils.hasPointer || !utils.hasTouch,disableMouse : utils.hasPointer || utils.hasTouch,startX: 0, //横向滑动的的初始值startY: 0,//竖直滑动的初始值scrollY: true, //是否运行竖直滑动...};

当然还有一些包括指示器的一些参数(自定义、样式等等),文档上貌似都没列出来,小伙伴只能去看源码了.

然后就是比较重要的几个初始化了:

    this._init();//初始化()this.refresh(); //获取一些基本参数(如果scroller的高度变化了需要调用此方法)this.scrollTo(this.options.startX, this.options.startY);//调整初始位置this.enable();//默认允许滑动
_init: function () {this._initEvents();//绑定事件(鼠标滑动、touch等等)if ( this.options.scrollbars || this.options.indicators ) {this._initIndicators();//如果需要显示指示器的话,就去初始化指示器}if ( this.options.mouseWheel ) {this._initWheel(); //监听鼠标滑动事件(默认打开)}if ( this.options.snap ) {this._initSnap();//翻页效果实现(默认关闭)}if ( this.options.keyBindings ) {this._initKeys();//绑定上下左右按键出发滚动(默认关闭)}// INSERT POINT: _init},

那么既然iscroll禁用了默认的滑动,那么它是怎么滑动的呢?小伙伴猜也应该猜到了,就是监听元素(默认wrapper)的鼠标滑动、touch等等事件然后做出相应计算:

_initEvents: function (remove) {var eventType = remove ? utils.removeEvent : utils.addEvent,target = this.options.bindToWrapper ? this.wrapper : window;eventType(window, 'orientationchange', this);//当转换屏幕的时候refresh重置参数eventType(window, 'resize', this);//当window的size变换的时候时候refresh重置参数if ( this.options.click ) {//wrapper的点击事件eventType(this.wrapper, 'click', this, true);}if ( !this.options.disableMouse ) {//监听鼠标事件eventType(this.wrapper, 'mousedown', this);eventType(target, 'mousemove', this);eventType(target, 'mousecancel', this);eventType(target, 'mouseup', this);}if ( utils.hasPointer && !this.options.disablePointer ) {//处理指针事件,主要处理tap事件eventType(this.wrapper, utils.prefixPointerEvent('pointerdown'), this);eventType(target, utils.prefixPointerEvent('pointermove'), this);eventType(target, utils.prefixPointerEvent('pointercancel'), this);eventType(target, utils.prefixPointerEvent('pointerup'), this);}if ( utils.hasTouch && !this.options.disableTouch ) {//监听touch事件eventType(this.wrapper, 'touchstart', this);eventType(target, 'touchmove', this);eventType(target, 'touchcancel', this);eventType(target, 'touchend', this);}eventType(this.scroller, 'transitionend', this);//监听transition过渡动画过程eventType(this.scroller, 'webkitTransitionEnd', this);eventType(this.scroller, 'oTransitionEnd', this);eventType(this.scroller, 'MSTransitionEnd', this);},

我们重点看一下,当我们的手指滑动的时候,scroller元素是怎么滑动的:

handleEvent: function (e) {switch ( e.type ) {...case 'touchmove':case 'pointermove':case 'MSPointerMove':case 'mousemove':this._move(e);break;...}}

处理滑动事件:

_move: function (e) {if ( !this.enabled || utils.eventType[e.type] !== this.initiated ) {return;}if ( this.options.preventDefault ) {    // increases performance on Android? TODO: check!e.preventDefault();}var point       = e.touches ? e.touches[0] : e,deltaX      = point.pageX - this.pointX,deltaY      = point.pageY - this.pointY,timestamp   = utils.getTime(),newX, newY,absDistX, absDistY;this.pointX     = point.pageX;this.pointY     = point.pageY;this.distX      += deltaX;this.distY      += deltaY;absDistX        = Math.abs(this.distX);absDistY        = Math.abs(this.distY);// We need to move at least 10 pixels for the scrolling to initiateif ( timestamp - this.endTime > 300 && (absDistX < 10 && absDistY < 10) ) {return;}// If you are scrolling in one direction lock the otherif ( !this.directionLocked && !this.options.freeScroll ) {if ( absDistX > absDistY + this.options.directionLockThreshold ) {this.directionLocked = 'h';     // lock horizontally} else if ( absDistY >= absDistX + this.options.directionLockThreshold ) {this.directionLocked = 'v';     // lock vertically} else {this.directionLocked = 'n';     // no lock}}if ( this.directionLocked == 'h' ) {if ( this.options.eventPassthrough == 'vertical' ) {e.preventDefault();} else if ( this.options.eventPassthrough == 'horizontal' ) {this.initiated = false;return;}deltaY = 0;} else if ( this.directionLocked == 'v' ) {if ( this.options.eventPassthrough == 'horizontal' ) {e.preventDefault();} else if ( this.options.eventPassthrough == 'vertical' ) {this.initiated = false;return;}deltaX = 0;}deltaX = this.hasHorizontalScroll ? deltaX : 0;deltaY = this.hasVerticalScroll ? deltaY : 0;newX = this.x + deltaX;newY = this.y + deltaY;// Slow down if outside of the boundariesif ( newX > 0 || newX < this.maxScrollX ) {newX = this.options.bounce ? this.x + deltaX / 3 : newX > 0 ? 0 : this.maxScrollX;}if ( newY > 0 || newY < this.maxScrollY ) {newY = this.options.bounce ? this.y + deltaY / 3 : newY > 0 ? 0 : this.maxScrollY;}this.directionX = deltaX > 0 ? -1 : deltaX < 0 ? 1 : 0;this.directionY = deltaY > 0 ? -1 : deltaY < 0 ? 1 : 0;if ( !this.moved ) {this._execEvent('scrollStart');}this.moved = true;this._translate(newX, newY);/* REPLACE START: _move */if ( timestamp - this.startTime > 300 ) {this.startTime = timestamp;this.startX = this.x;this.startY = this.y;}/* REPLACE END: _move */},

代码有点多,小伙伴别被吓住了哈,主要就是计算上一次与这一次滑动的距离,然后设置元素的偏移量,我们可以看到最后有一行代码:

this._translate(newX, newY);
_translate: function (x, y) {if ( this.options.useTransform ) {/* REPLACE START: _translate */this.scrollerStyle[utils.style.transform] = 'translate(' + x + 'px,' + y + 'px)' + this.translateZ;/* REPLACE END: _translate */} else {x = Math.round(x);y = Math.round(y);this.scrollerStyle.left = x + 'px';this.scrollerStyle.top = y + 'px';}this.x = x;this.y = y;if ( this.indicators ) {for ( var i = this.indicators.length; i--; ) {this.indicators[i].updatePosition();}}// INSERT POINT: _translate},

可以看到,最后也就是设置x轴或者y轴的偏移量:

x = Math.round(x);y = Math.round(y);this.scrollerStyle.left = x + 'px';this.scrollerStyle.top = y + 'px';

原理其实很简单,但是iscroll可不单单如此简单哈~~ 她可不简单,慢慢研究吧!! 睡啦睡啦~~生命重要!!!小伙伴下期见哈,大牛勿喷!!

前端入门之(我与iscroll的不期而遇)相关推荐

  1. 前端入门 前端自学路线 web开发前端如何学习

    本文介绍前端入门之路,以及之后对前端应该怎么学,大概学哪些东西.作者在前端.后端入门的时候,花了大量时间到CSDN.知乎.百度上去找资料,但是有的说的不是太复杂, 就是一句话带过,那个时候很苦恼.现在 ...

  2. web前端入门学习 css(1)

    黑马程序员Web前端入门教程,零基础前端视频教程pink老师_html5+css3 文章目录 html局限性 css简介(层叠样式表.级联样式表.css样式表) css语法规范 css代码样式风格(推 ...

  3. web前端入门学习 html5(1)

    web前端入门基础教程,最适合零基础前端小白的视频教程html5+css3 文章目录 html 浏览器内核 web标注 语法规范 html基本结构标签 web常用开发工具 vscode基本使用 文档类 ...

  4. web前端入门必知的10个技术

    随着HTML5的发展和普及,了解HTML5将成为Web开发人员的必修课.如何把网页做得更美观,对用户更有吸引力,不仅是企业对前端开发人员要求,更是一个合格的web前端工程师的自我修行.今天小编就跟大家 ...

  5. Web前端入门学习(5)——浮动原理及清除浮动

    浮动原理及清除浮动 上节回顾 在上节的<Web前端入门学习(4)-- 块级元素和行内元素之特征与转换>中(http://cherry360.blog.51cto.com/12176744/ ...

  6. 零基础前端入门,真正难在哪里?简说编程思想和逻辑思维

    很多同学跟我说,学前端学的很迷茫, 就这样,问他为啥迷茫吧,说也说不出来啥具体的.就是也学了一堆东西,也确实都是前端开发工作当中要用的.但依然不知道前路如何. 这里就有一个"前端入门的标准& ...

  7. 前端如何实现音乐盒胶盘的转动_郑州Web前端入门教程之如何实现图片优化?

    统计数据显示,图片内容已经占据互联网内容总量的62%,因此想要优化网站性能,图片绝对是优化的热点和重点.图片优化是Web前端工程师必须要掌握的知识点,在接下来的郑州Web前端入门教程就给大家讲解一下如 ...

  8. vuex 源码分析_前端入门之(vuex-router-sync解析)

    前端入门之(vuex-router-sync解析) 发布时间:2018-11-14 13:31, 浏览次数:513 , 标签: vuex router sync 前言:vue全家桶的内容我们已经研究过 ...

  9. html前端页面的基本骨架是,web前端入门到实战:css实现的骨架屏方案

    web前端入门到实战:css实现的骨架屏方案 发布时间:2020-08-04 01:32:03 来源:51CTO 阅读:152 作者:前端向南 优点 简单,不需要工程,不用puppeteer生成骨架d ...

最新文章

  1. android源生setting华为,Android 设置默认桌面,默认应用,辅助功能,电池优化,设备管理器,悬浮窗等...
  2. 非递减数列JAVA_C语言实现两个递减数列中寻找某一个数
  3. GetCurrentProcessID、OpenProcessToken、LookupPrivilegeValue、AdjustTokenPrivileges
  4. linux ll命令无效
  5. 【51单片机快速入门指南】4.4.2:Mahony AHRS 九轴姿态融合获取四元数、欧拉角
  6. 真实临在--摘自{《信仰在我家》}
  7. day21 java的八大包装类
  8. AttributeError: ‘Model‘ object has no attribute ‘predict_classes‘ 的解决方案
  9. 新加用户被保护的解决办法
  10. 《How to bake LightMap》
  11. 【车间调度】基于matlab模拟退火算法求解车间调度问题【含Matlab源码 894期】
  12. 显示最新的Picasaweb上传
  13. spring MVC之Annotated Controllers
  14. 【SpringMVC】Resultful风格映射url
  15. [历朝通俗演义-蔡东藩-前汉]第012回 戕县令刘邦发迹 杀郡守项梁举兵
  16. Bash解析器常用快捷键
  17. Titan漫谈(一)
  18. H5分享页面背景音乐及播放视频
  19. 计算机错误678,宽带连接错误678,教您宽带连接错误678怎么解决
  20. 浏览器的内核种类及检测

热门文章

  1. 如何成为有效学习的高手(笔记)
  2. PHP-简单理解递归
  3. 微信小程序实现下拉刷新功能
  4. Delphi @ ^
  5. 求n的阶乘的算法框图_当代程序员必备技能(算法)之:递归详解 - Java斗帝之路...
  6. 【WINDOWS / DOS 批处理】for命令详解(八)
  7. STM32开发板搭建开发环境之安装篇
  8. 后台监控服务器信息,服务器后台聊天监控
  9. redis缓存失效时间设为多少_Redis缓存过期失效机制
  10. String类型转Long类型需要注意的问题