【iScroll源码学习01】准备阶段 - 叶小钗
【iScroll源码学习01】准备阶段 - 叶小钗
① viewport相关知识点(device-width等)
② CSS3硬件加速
③ 如何暂停CSS动画
④ e.preventDefault导致文本不能获取焦点解决方案
......
当然,我们写的demo自然不能和iScroll本身的代码比肩,但是demo过程中我们也大概了解了iScroll代码过程中需要注意的一些问题
于是,今天让我们进入iScroll的学习吧
初探iScroll

- 1 <!DOCTYPE html>
- 2 <html>
- 3 <head>
- 4 <meta charset="utf-8">
- 5 <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0, minimum-scale=1.0, maximum-scale=1.0">
- 6
- 7 <title>iScroll demo: scrollbars</title>
- 8
- 9 <script type="text/javascript" src="../../build/iscroll.js"></script>
- 10
- 11
- 12 <script type="text/javascript">
- 13
- 14 var myScroll;
- 15
- 16 function loaded () {
- 17 myScroll = new IScroll('#wrapper', {
- 18 scrollbars: true,
- 19 mouseWheel: true,
- 20 interactiveScrollbars: true,
- 21 shrinkScrollbars: 'scale',
- 22 fadeScrollbars: true
- 23 });
- 24 }
- 25
- 26 document.addEventListener('touchmove', function (e) { e.preventDefault(); }, false);
- 27
- 28 </script>
- 29
- 30 <style type="text/css">
- 31 * {
- 32 -webkit-box-sizing: border-box;
- 33 -moz-box-sizing: border-box;
- 34 box-sizing: border-box;
- 35 }
- 36
- 37 html {
- 38 -ms-touch-action: none;
- 39 }
- 40
- 41 body,ul,li {
- 42 padding: 0;
- 43 margin: 0;
- 44 border: 0;
- 45 }
- 46
- 47 body {
- 48 font-size: 12px;
- 49 font-family: ubuntu, helvetica, arial;
- 50 overflow: hidden; /* this is important to prevent the whole page to bounce */
- 51 }
- 52
- 53 #header {
- 54 position: absolute;
- 55 z-index: 2;
- 56 top: 0;
- 57 left: 0;
- 58 width: 100%;
- 59 height: 45px;
- 60 line-height: 45px;
- 61 background: #CD235C;
- 62 padding: 0;
- 63 color: #eee;
- 64 font-size: 20px;
- 65 text-align: center;
- 66 font-weight: bold;
- 67 }
- 68
- 69 #footer {
- 70 position: absolute;
- 71 z-index: 2;
- 72 bottom: 0;
- 73 left: 0;
- 74 width: 100%;
- 75 height: 48px;
- 76 background: #444;
- 77 padding: 0;
- 78 border-top: 1px solid #444;
- 79 }
- 80
- 81 #wrapper {
- 82 position: absolute;
- 83 z-index: 1;
- 84 top: 45px;
- 85 bottom: 48px;
- 86 left: 0;
- 87 width: 100%;
- 88 background: #ccc;
- 89 overflow: hidden;
- 90 }
- 91
- 92 #scroller {
- 93 position: absolute;
- 94 z-index: 1;
- 95 -webkit-tap-highlight-color: rgba(0,0,0,0);
- 96 width: 100%;
- 97 -webkit-transform: translateZ(0);
- 98 -moz-transform: translateZ(0);
- 99 -ms-transform: translateZ(0);
- 100 -o-transform: translateZ(0);
- 101 transform: translateZ(0);
- 102 -webkit-touch-callout: none;
- 103 -webkit-user-select: none;
- 104 -moz-user-select: none;
- 105 -ms-user-select: none;
- 106 user-select: none;
- 107 -webkit-text-size-adjust: none;
- 108 -moz-text-size-adjust: none;
- 109 -ms-text-size-adjust: none;
- 110 -o-text-size-adjust: none;
- 111 text-size-adjust: none;
- 112 }
- 113
- 114 #scroller ul {
- 115 list-style: none;
- 116 padding: 0;
- 117 margin: 0;
- 118 width: 100%;
- 119 text-align: left;
- 120 }
- 121
- 122 #scroller li {
- 123 padding: 0 10px;
- 124 height: 40px;
- 125 line-height: 40px;
- 126 border-bottom: 1px solid #ccc;
- 127 border-top: 1px solid #fff;
- 128 background-color: #fafafa;
- 129 font-size: 14px;
- 130 }
- 131
- 132 </style>
- 133 </head>
- 134 <body onload="loaded()">
- 135 <div id="header">iScroll</div>
- 136
- 137 <div id="wrapper">
- 138 <div id="scroller">
- 139 <ul>
- 140 <li>Pretty row 1</li>
- 141 <li>Pretty row 2</li>
- 142 <li>Pretty row 3</li>
- 143 <li>Pretty row 4</li>
- 144 <li>Pretty row 5</li>
- 145 <li>Pretty row 6</li>
- 146 <li>Pretty row 7</li>
- 147 <li>Pretty row 8</li>
- 148 <li>Pretty row 9</li>
- 149 <li>Pretty row 10</li>
- 150 <li>Pretty row 11</li>
- 151 <li>Pretty row 12</li>
- 152 <li>Pretty row 13</li>
- 153 <li>Pretty row 14</li>
- 154 <li>Pretty row 15</li>
- 155 <li>Pretty row 16</li>
- 156 <li>Pretty row 17</li>
- 157 <li>Pretty row 18</li>
- 158 <li>Pretty row 19</li>
- 159 <li>Pretty row 20</li>
- 160 <li>Pretty row 21</li>
- 161 <li>Pretty row 22</li>
- 162 <li>Pretty row 23</li>
- 163 <li>Pretty row 24</li>
- 164 <li>Pretty row 25</li>
- 165 <li>Pretty row 26</li>
- 166 <li>Pretty row 27</li>
- 167 <li>Pretty row 28</li>
- 168 <li>Pretty row 29</li>
- 169 <li>Pretty row 30</li>
- 170 <li>Pretty row 31</li>
- 171 <li>Pretty row 32</li>
- 172 <li>Pretty row 33</li>
- 173 <li>Pretty row 34</li>
- 174 <li>Pretty row 35</li>
- 175 <li>Pretty row 36</li>
- 176 <li>Pretty row 37</li>
- 177 <li>Pretty row 38</li>
- 178 <li>Pretty row 39</li>
- 179 <li>Pretty row 40</li>
- 180 <li>Pretty row 41</li>
- 181 <li>Pretty row 42</li>
- 182 <li>Pretty row 43</li>
- 183 <li>Pretty row 44</li>
- 184 <li>Pretty row 45</li>
- 185 <li>Pretty row 46</li>
- 186 <li>Pretty row 47</li>
- 187 <li>Pretty row 48</li>
- 188 <li>Pretty row 49</li>
- 189 <li>Pretty row 50</li>
- 190
- 191 <li>Pretty row 1</li>
- 192 <li>Pretty row 2</li>
- 193 <li>Pretty row 3</li>
- 194 <li>Pretty row 4</li>
- 195 <li>Pretty row 5</li>
- 196 <li>Pretty row 6</li>
- 197 <li>Pretty row 7</li>
- 198 <li>Pretty row 8</li>
- 199 <li>Pretty row 9</li>
- 200 <li>Pretty row 10</li>
- 201 <li>Pretty row 11</li>
- 202 <li>Pretty row 12</li>
- 203 <li>Pretty row 13</li>
- 204 <li>Pretty row 14</li>
- 205 <li>Pretty row 15</li>
- 206 <li>Pretty row 16</li>
- 207 <li>Pretty row 17</li>
- 208 <li>Pretty row 18</li>
- 209 <li>Pretty row 19</li>
- 210 <li>Pretty row 20</li>
- 211 <li>Pretty row 21</li>
- 212 <li>Pretty row 22</li>
- 213 <li>Pretty row 23</li>
- 214 <li>Pretty row 24</li>
- 215 <li>Pretty row 25</li>
- 216 <li>Pretty row 26</li>
- 217 <li>Pretty row 27</li>
- 218 <li>Pretty row 28</li>
- 219 <li>Pretty row 29</li>
- 220 <li>Pretty row 30</li>
- 221 <li>Pretty row 31</li>
- 222 <li>Pretty row 32</li>
- 223 <li>Pretty row 33</li>
- 224 <li>Pretty row 34</li>
- 225 <li>Pretty row 35</li>
- 226 <li>Pretty row 36</li>
- 227 <li>Pretty row 37</li>
- 228 <li>Pretty row 38</li>
- 229 <li>Pretty row 39</li>
- 230 <li>Pretty row 40</li>
- 231 <li>Pretty row 41</li>
- 232 <li>Pretty row 42</li>
- 233 <li>Pretty row 43</li>
- 234 <li>Pretty row 44</li>
- 235 <li>Pretty row 45</li>
- 236 <li>Pretty row 46</li>
- 237 <li>Pretty row 47</li>
- 238 <li>Pretty row 48</li>
- 239 <li>Pretty row 49</li>
- 240 <li>Pretty row 50</li>
- 241
- 242 <li>Pretty row 1</li>
- 243 <li>Pretty row 2</li>
- 244 <li>Pretty row 3</li>
- 245 <li>Pretty row 4</li>
- 246 <li>Pretty row 5</li>
- 247 <li>Pretty row 6</li>
- 248 <li>Pretty row 7</li>
- 249 <li>Pretty row 8</li>
- 250 <li>Pretty row 9</li>
- 251 <li>Pretty row 10</li>
- 252 <li>Pretty row 11</li>
- 253 <li>Pretty row 12</li>
- 254 <li>Pretty row 13</li>
- 255 <li>Pretty row 14</li>
- 256 <li>Pretty row 15</li>
- 257 <li>Pretty row 16</li>
- 258 <li>Pretty row 17</li>
- 259 <li>Pretty row 18</li>
- 260 <li>Pretty row 19</li>
- 261 <li>Pretty row 20</li>
- 262 <li>Pretty row 21</li>
- 263 <li>Pretty row 22</li>
- 264 <li>Pretty row 23</li>
- 265 <li>Pretty row 24</li>
- 266 <li>Pretty row 25</li>
- 267 <li>Pretty row 26</li>
- 268 <li>Pretty row 27</li>
- 269 <li>Pretty row 28</li>
- 270 <li>Pretty row 29</li>
- 271 <li>Pretty row 30</li>
- 272 <li>Pretty row 31</li>
- 273 <li>Pretty row 32</li>
- 274 <li>Pretty row 33</li>
- 275 <li>Pretty row 34</li>
- 276 <li>Pretty row 35</li>
- 277 <li>Pretty row 36</li>
- 278 <li>Pretty row 37</li>
- 279 <li>Pretty row 38</li>
- 280 <li>Pretty row 39</li>
- 281 <li>Pretty row 40</li>
- 282 <li>Pretty row 41</li>
- 283 <li>Pretty row 42</li>
- 284 <li>Pretty row 43</li>
- 285 <li>Pretty row 44</li>
- 286 <li>Pretty row 45</li>
- 287 <li>Pretty row 46</li>
- 288 <li>Pretty row 47</li>
- 289 <li>Pretty row 48</li>
- 290 <li>Pretty row 49</li>
- 291 <li>Pretty row 50</li>
- 292
- 293 <li>Pretty row 1</li>
- 294 <li>Pretty row 2</li>
- 295 <li>Pretty row 3</li>
- 296 <li>Pretty row 4</li>
- 297 <li>Pretty row 5</li>
- 298 <li>Pretty row 6</li>
- 299 <li>Pretty row 7</li>
- 300 <li>Pretty row 8</li>
- 301 <li>Pretty row 9</li>
- 302 <li>Pretty row 10</li>
- 303 <li>Pretty row 11</li>
- 304 <li>Pretty row 12</li>
- 305 <li>Pretty row 13</li>
- 306 <li>Pretty row 14</li>
- 307 <li>Pretty row 15</li>
- 308 <li>Pretty row 16</li>
- 309 <li>Pretty row 17</li>
- 310 <li>Pretty row 18</li>
- 311 <li>Pretty row 19</li>
- 312 <li>Pretty row 20</li>
- 313 <li>Pretty row 21</li>
- 314 <li>Pretty row 22</li>
- 315 <li>Pretty row 23</li>
- 316 <li>Pretty row 24</li>
- 317 <li>Pretty row 25</li>
- 318 <li>Pretty row 26</li>
- 319 <li>Pretty row 27</li>
- 320 <li>Pretty row 28</li>
- 321 <li>Pretty row 29</li>
- 322 <li>Pretty row 30</li>
- 323 <li>Pretty row 31</li>
- 324 <li>Pretty row 32</li>
- 325 <li>Pretty row 33</li>
- 326 <li>Pretty row 34</li>
- 327 <li>Pretty row 35</li>
- 328 <li>Pretty row 36</li>
- 329 <li>Pretty row 37</li>
- 330 <li>Pretty row 38</li>
- 331 <li>Pretty row 39</li>
- 332 <li>Pretty row 40</li>
- 333 <li>Pretty row 41</li>
- 334 <li>Pretty row 42</li>
- 335 <li>Pretty row 43</li>
- 336 <li>Pretty row 44</li>
- 337 <li>Pretty row 45</li>
- 338 <li>Pretty row 46</li>
- 339 <li>Pretty row 47</li>
- 340 <li>Pretty row 48</li>
- 341 <li>Pretty row 49</li>
- 342 <li>Pretty row 50</li>
- 343 </ul>
- 344 </div>
- 345 </div>
- 346
- 347 <div id="footer"></div>
- 348 </body>
- 349 </html>
http://sandbox.runjs.cn/show/pscjy3a3
下面是他初始化时候的核心代码:
- 1 var myScroll;
- 2 function loaded () {
- 3 myScroll = new IScroll('#wrapper', {
- 4 scrollbars: true,
- 5 mouseWheel: true,
- 6 interactiveScrollbars: true,
- 7 shrinkScrollbars: 'scale',
- 8 fadeScrollbars: true
- 9 });
- 10 }
- 11 document.addEventListener('touchmove', function (e) { e.preventDefault(); }, false);
真不得不说,这个滑动起来感觉挺不错的,第一感觉有几大特点:
看看他的构造函数,然后去网上找一点参数说明(Iscroll应用文档):
- hScroll: true, //是否水平滚动
- vScroll: true, //是否垂直滚动
- x: 0, //滚动水平初始位置
- y: 0, //滚动垂直初始位置
- snap: true, //值可以为true或是DOM元素的tagname,当为true时,对齐的坐标会根据可滚动的位置和滚动区域计算得到可滑动几页,如果为tagname,则滑动会对齐到元素上
- bounce: true, //是否超过实际位置反弹
- bounceLock: false, //当内容少于滚动是否可以反弹,这个实际用处不大
- momentum: true, //动量效果,拖动惯性
- lockDirection: true, //当水平滚动和垂直滚动同时生效时,当拖动开始是否锁定另一边的拖动
- useTransform: true, //是否使用CSS形变
- useTransition: false, //是否使用CSS变换
- topOffset: 0, //已经滚动的基准值(一般情况用不到)
- checkDOMChanges: false, //是否自动检测内容变化(这个检测不是很准)
- //Scrollbar相关参数,通过scrollbar这些参数可以配置iscroll的滚动条,通过scrollbarClass可以自己定义一套滚动条的样式。
- hScrollbar: true, //是否显示水平滚动条
- vScrollbar: true, //同上垂直滚动条
- fixedScrollbar: isAndroid, //对andriod的fixed
- hideScrollbar: isIDevice, //是否隐藏滚动条
- fadeScrollbar: isIDevice && has3d, //滚动条是否渐隐渐显
- scrollbarClass: '', //自定义滚动条的样式名
- //Zoom放大相关的参数,通过它,对于一个固定显示图片区域的类似应用,可以非常简单的做到固定滚动,包括两指放大的应用。
- zoom: false, //默认是否放大
- zoomMin: 1, //放大的最小倍数
- zoomMax: 4, //最大倍数
- doubleTapZoom: 2, //双触放大几倍
- wheelAction: 'scroll', //鼠标滚动行为(还可以是zoom)
- //自定义Events相关参数
- onRefresh: null, //refresh 的回调,关于自身何时调用refresh 后面会继续谈到
- onBeforeScrollStart: function(e){ e.preventDefault(); }, //开始滚动前的时间回调,默认是阻止浏览器默认行为
- onScrollStart: null, //开始滚动的回调
- onBeforeScrollMove: null, //在内容移动前的回调
- onScrollMove: null, //内容移动的回调
- onBeforeScrollEnd: null, //在滚动结束前的回调
- onScrollEnd: null, //在滚动完成后的回调
- onTouchEnd: null, //手离开屏幕后的回调
- onDestroy: null, //销毁实例的回调
- onZoomStart: null, //开始放大前的回调
- onZoom: null, //放大的回调
- onZoomEnd: null //放大完成后的回调
- Iscroll 提供的调用方法
- destroy
- 顾名思义,是用来销毁你实例化的iScroll 实例,包括之前绑定的所有iscroll 事件。
- refresh
- 这个方法非常有用,当你的滚动区域的内容发生改变 或是 滚动区域不正确,都用通过调用refresh 来使得iscroll 重新计算滚动的区域,包括滚动条,来使得iscroll 适合当前的dom。
- scrollTo
- 这个方法接受4个参数 x, y, time, relative x 为移动的x轴坐标,y为移动的y轴坐标, time为移动时间,relative表示是否相对当前位置。
- scrollToElement
- 这个方法实际上是对scrollTo的进一步封装,接受两个参数(el,time),el为需要滚动到的元素引用,time为滚动时间。
- scrollToPage
- 此方法接受三个参数(pageX,pageY,time) 当滚动内容的高宽大于滚动范围时,iscroll 会自动分页,然后就能使用scrollToPage方法滚动到页面。当然,当hscroll 为false 的时候,不能左右滚动。pageX这个参数就失去效果
- disable
- 调用这个方法会立即停止动画滚动,并且把滚动位置还原成0,取消绑定touchmove, touchend、touchcancel事件。
- enable
- 调用这个方法,使得iscroll恢复默认正常状态
- stop
- 立即停止动画
- zoom
- 改变内容的大小倍数,此方法接受4个参数,x,y,scale,time 分别表示的意思为,放大的基准坐标,以及放大倍数,动画时间
- isReady
- 当iscroll 没有处于正在滚动,没有移动过,没有改变大小时,此值为true
功能非常丰富啊,对于应用来说够用了,但是一些功能我这里用不到,就忽略了
功能很好,size为48k,压缩后稍微好一点,将近2000行的代码,作为基础库来说,有点大了,比整个zepto还大
而且整个库的注释写的不好,好像压根就没写......不知道阅读上会不会有障碍,于是我们进入源码
iScroll笔记
requestAnimationFrame
- 1 var rAF = window.requestAnimationFrame ||
- 2 window.webkitRequestAnimationFrame ||
- 3 window.mozRequestAnimationFrame ||
- 4 window.oRequestAnimationFrame ||
- 5 window.msRequestAnimationFrame ||
- 6 function (callback) { window.setTimeout(callback, 1000 / 60); };
这段代码是要做能力检测的,这里来说一下requestAnimationFrame这个东西(参考: http://www.kimhou.com/?p=155 )
在jquery中javascript动画是通过定时器(settimeout)实现的,没一个时间点改变一点style,而CSS3后便推出了transition以及animation开始实现动画
我们昨天提到的硬件加速,也是CSS3相关的东西。CSS3动画效率与顺畅度比Js高,所以现在动画开始楚河汉界了
js的好处是可以很好的控制动画状态、css动画带来的性能较高,但是控制度就低一点(是很低)
定时器实现动画
- 1 <html xmlns="http://www.w3.org/1999/xhtml">
- 2 <head>
- 3 <title></title>
- 4 </head>
- 5 <body>
- 6 <div id="el" style="position: absolute;">
- 7 Javascript时钟实现动画
- 8 </div>
- 9 <script src="zepto.js" type="text/javascript"></script>
- 10 <script type="text/javascript">
- 11 var pos = 0;
- 12 var final = 200;
- 13 var dir = 0;
- 14 var el = $('#el');
- 15 function upLeft() {
- 16 var left = parseInt(el.css('left')) || 0;
- 17 if (left >= final) dir = 1;
- 18 if (left <= pos) dir = 0;
- 19
- 20 if (dir == 0) {
- 21 left++;
- 22 el.css('left', left + 'px');
- 23 setTimeout(upLeft);
- 24 } else {
- 25 left--;
- 26 el.css('left', left + 'px');
- 27 setTimeout(upLeft);
- 28 }
- 29 }
- 30 upLeft();
- 31 </script>
- 32 </body>
- 33 </html>
效果见下面
这便是使用javascript实现的一个最简单的动画,各位看到了,里面的定时器不停的在运动,性能不差的话我就改名叫素还真了
这个阶段,比较棘手的问题往往在延迟的计算,间隔要短所以动画顺畅,但是浏览器渲染也得耗费时间,这个就要求每次变化留给浏览器的时间够长了(60HZ/75Hz)
所以之前javascript的间隔一般为20左右,这个时候的动画比较流畅,这个数字与浏览器的频率比较接近(1000/60)
- function (callback) { window.setTimeout(callback, 1000 / 60); }
但是通过前面对时钟的学习,我们知道settimeout只是将回调函数加入UI线程队列,那么同一时间有多个动画待执行的话,延迟就发生了,效果也会打折扣
这里原来用js实现坦克大战的朋友就会有所体会了
javascript问题解决
CSS的transition与animations的优势在于浏览器知道哪些动画将会发生,所以动画会得到正确的间隔来刷新UI(javascript当然不知道)
于是这里就多了一个方法:RequestAnimationFrame,他可以告诉浏览器自己要执行动画了,于是js的动画事实上得到了优化
RequestAnimationFrame接受一个参数,也就是屏幕重绘前会调用的函数,这个函数用来改变dom样式,这个方法使用有点类似于settimeout
- 1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
- 2 <html xmlns="http://www.w3.org/1999/xhtml">
- 3 <head>
- 4 <title></title>
- 5 </head>
- 6 <body>
- 7
- 8 <div id="el" style="position: absolute;">
- 9 Javascript时钟实现动画
- 10 </div>
- 11 <script src="zepto.js" type="text/javascript"></script>
- 12 <script type="text/javascript">
- 13 var rAF = window.requestAnimationFrame ||
- 14 window.webkitRequestAnimationFrame ||
- 15 window.mozRequestAnimationFrame ||
- 16 window.oRequestAnimationFrame ||
- 17 window.msRequestAnimationFrame ||
- 18 function (callback) { window.setTimeout(callback, 1000 / 60); };
- 19 var pos = 0;
- 20 var final = 200;
- 21 var dir = 0;
- 22 var el = $('#el');
- 23 function upLeft() {
- 24 var left = parseInt(el.css('left')) || 0;
- 25 if (left >= final) dir = 1;
- 26 if (left <= pos) dir = 0;
- 27
- 28 if (dir == 0) {
- 29 left++;
- 30 el.css('left', left + 'px');
- 31 rAF(upLeft);
- 32 } else {
- 33 left--;
- 34 el.css('left', left + 'px');
- 35 rAF(upLeft);
- 36 }
- 37 }
- 38 upLeft();
- 39 </script>
- 40 </body>
- 41 </html>
这个动画将会有不一样的感受:
动画效果相关,各位自己去感受,代码各位可以自己调整。如此这个方法其实就是做javascript动画处理优化方案的
PS:尼玛,iScroll第一段就搞了这么久啊这么久
utils
然后iScroll将自己下面会用到的常用操作封装到了这个对象中——utils。

- 1 var utils = (function () {
- 2 var me = {};
- 3
- 4 var _elementStyle = document.createElement('div').style;
- 5 var _vendor = (function () {
- 6 var vendors = ['t', 'webkitT', 'MozT', 'msT', 'OT'],
- 7 transform,
- 8 i = 0,
- 9 l = vendors.length;
- 10
- 11 for ( ; i < l; i++ ) {
- 12 transform = vendors[i] + 'ransform';
- 13 if ( transform in _elementStyle ) return vendors[i].substr(0, vendors[i].length-1);
- 14 }
- 15
- 16 return false;
- 17 })();
- 18
- 19 function _prefixStyle (style) {
- 20 if ( _vendor === false ) return false;
- 21 if ( _vendor === '' ) return style;
- 22 return _vendor + style.charAt(0).toUpperCase() + style.substr(1);
- 23 }
- 24
- 25 me.getTime = Date.now || function getTime () { return new Date().getTime(); };
- 26
- 27 me.extend = function (target, obj) {
- 28 for ( var i in obj ) {
- 29 target[i] = obj[i];
- 30 }
- 31 };
- 32
- 33 me.addEvent = function (el, type, fn, capture) {
- 34 el.addEventListener(type, fn, !!capture);
- 35 };
- 36
- 37 me.removeEvent = function (el, type, fn, capture) {
- 38 el.removeEventListener(type, fn, !!capture);
- 39 };
- 40
- 41 me.momentum = function (current, start, time, lowerMargin, wrapperSize) {
- 42 var distance = current - start,
- 43 speed = Math.abs(distance) / time,
- 44 destination,
- 45 duration,
- 46 deceleration = 0.0006;
- 47
- 48 destination = current + ( speed * speed ) / ( 2 * deceleration ) * ( distance < 0 ? -1 : 1 );
- 49 duration = speed / deceleration;
- 50
- 51 if ( destination < lowerMargin ) {
- 52 destination = wrapperSize ? lowerMargin - ( wrapperSize / 2.5 * ( speed / 8 ) ) : lowerMargin;
- 53 distance = Math.abs(destination - current);
- 54 duration = distance / speed;
- 55 } else if ( destination > 0 ) {
- 56 destination = wrapperSize ? wrapperSize / 2.5 * ( speed / 8 ) : 0;
- 57 distance = Math.abs(current) + destination;
- 58 duration = distance / speed;
- 59 }
- 60
- 61 return {
- 62 destination: Math.round(destination),
- 63 duration: duration
- 64 };
- 65 };
- 66
- 67 var _transform = _prefixStyle('transform');
- 68
- 69 me.extend(me, {
- 70 hasTransform: _transform !== false,
- 71 hasPerspective: _prefixStyle('perspective') in _elementStyle,
- 72 hasTouch: 'ontouchstart' in window,
- 73 hasPointer: navigator.msPointerEnabled,
- 74 hasTransition: _prefixStyle('transition') in _elementStyle
- 75 });
- 76
- 77 // This should find all Android browsers lower than build 535.19 (both stock browser and webview)
- 78 me.isBadAndroid = /Android/.test(window.navigator.appVersion) && !(/Chrome\/\d/.test(window.navigator.appVersion));
- 79
- 80 me.extend(me.style = {}, {
- 81 transform: _transform,
- 82 transitionTimingFunction: _prefixStyle('transitionTimingFunction'),
- 83 transitionDuration: _prefixStyle('transitionDuration'),
- 84 transitionDelay: _prefixStyle('transitionDelay'),
- 85 transformOrigin: _prefixStyle('transformOrigin')
- 86 });
- 87
- 88 me.hasClass = function (e, c) {
- 89 var re = new RegExp("(^|\\s)" + c + "(\\s|$)");
- 90 return re.test(e.className);
- 91 };
- 92
- 93 me.addClass = function (e, c) {
- 94 if ( me.hasClass(e, c) ) {
- 95 return;
- 96 }
- 97
- 98 var newclass = e.className.split(' ');
- 99 newclass.push(c);
- 100 e.className = newclass.join(' ');
- 101 };
- 102
- 103 me.removeClass = function (e, c) {
- 104 if ( !me.hasClass(e, c) ) {
- 105 return;
- 106 }
- 107
- 108 var re = new RegExp("(^|\\s)" + c + "(\\s|$)", 'g');
- 109 e.className = e.className.replace(re, ' ');
- 110 };
- 111
- 112 me.offset = function (el) {
- 113 var left = -el.offsetLeft,
- 114 top = -el.offsetTop;
- 115
- 116 // jshint -W084
- 117 while (el = el.offsetParent) {
- 118 left -= el.offsetLeft;
- 119 top -= el.offsetTop;
- 120 }
- 121 // jshint +W084
- 122
- 123 return {
- 124 left: left,
- 125 top: top
- 126 };
- 127 };
- 128
- 129 me.preventDefaultException = function (el, exceptions) {
- 130 for ( var i in exceptions ) {
- 131 if ( exceptions[i].test(el[i]) ) {
- 132 return true;
- 133 }
- 134 }
- 135
- 136 return false;
- 137 };
- 138
- 139 me.extend(me.eventType = {}, {
- 140 touchstart: 1,
- 141 touchmove: 1,
- 142 touchend: 1,
- 143
- 144 mousedown: 2,
- 145 mousemove: 2,
- 146 mouseup: 2,
- 147
- 148 MSPointerDown: 3,
- 149 MSPointerMove: 3,
- 150 MSPointerUp: 3
- 151 });
- 152
- 153 me.extend(me.ease = {}, {
- 154 quadratic: {
- 155 style: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)',
- 156 fn: function (k) {
- 157 return k * ( 2 - k );
- 158 }
- 159 },
- 160 circular: {
- 161 style: 'cubic-bezier(0.1, 0.57, 0.1, 1)', // Not properly "circular" but this looks better, it should be (0.075, 0.82, 0.165, 1)
- 162 fn: function (k) {
- 163 return Math.sqrt( 1 - ( --k * k ) );
- 164 }
- 165 },
- 166 back: {
- 167 style: 'cubic-bezier(0.175, 0.885, 0.32, 1.275)',
- 168 fn: function (k) {
- 169 var b = 4;
- 170 return ( k = k - 1 ) * k * ( ( b + 1 ) * k + b ) + 1;
- 171 }
- 172 },
- 173 bounce: {
- 174 style: '',
- 175 fn: function (k) {
- 176 if ( ( k /= 1 ) < ( 1 / 2.75 ) ) {
- 177 return 7.5625 * k * k;
- 178 } else if ( k < ( 2 / 2.75 ) ) {
- 179 return 7.5625 * ( k -= ( 1.5 / 2.75 ) ) * k + 0.75;
- 180 } else if ( k < ( 2.5 / 2.75 ) ) {
- 181 return 7.5625 * ( k -= ( 2.25 / 2.75 ) ) * k + 0.9375;
- 182 } else {
- 183 return 7.5625 * ( k -= ( 2.625 / 2.75 ) ) * k + 0.984375;
- 184 }
- 185 }
- 186 },
- 187 elastic: {
- 188 style: '',
- 189 fn: function (k) {
- 190 var f = 0.22,
- 191 e = 0.4;
- 192
- 193 if ( k === 0 ) { return 0; }
- 194 if ( k == 1 ) { return 1; }
- 195
- 196 return ( e * Math.pow( 2, - 10 * k ) * Math.sin( ( k - f / 4 ) * ( 2 * Math.PI ) / f ) + 1 );
- 197 }
- 198 }
- 199 });
- 200
- 201 me.tap = function (e, eventName) {
- 202 var ev = document.createEvent('Event');
- 203 ev.initEvent(eventName, true, true);
- 204 ev.pageX = e.pageX;
- 205 ev.pageY = e.pageY;
- 206 e.target.dispatchEvent(ev);
- 207 };
- 208
- 209 me.click = function (e) {
- 210 var target = e.target,
- 211 ev;
- 212
- 213 if (target.tagName != 'SELECT' && target.tagName != 'INPUT' && target.tagName != 'TEXTAREA') {
- 214 ev = document.createEvent('MouseEvents');
- 215 ev.initMouseEvent('click', true, true, e.view, 1,
- 216 target.screenX, target.screenY, target.clientX, target.clientY,
- 217 e.ctrlKey, e.altKey, e.shiftKey, e.metaKey,
- 218 0, null);
- 219
- 220 ev._constructed = true;
- 221 target.dispatchEvent(ev);
- 222 }
- 223 };
- 224
- 225 return me;
- 226 })();
兼容性检测
很烦的事情一而再再而三的在浏览器上面出现,比如我们在chrome要定义动画参数得加上一个前缀webkit,然后ff要使用MozT,这个事情很烦,所以iScroll这段代码就在处理这个事情
- 1 var _vendor = (function () {
- 2 var vendors = ['t', 'webkitT', 'MozT', 'msT', 'OT'],
- 3 transform,
- 4 i = 0,
- 5 l = vendors.length;
- 6
- 7 for ( ; i < l; i++ ) {
- 8 transform = vendors[i] + 'ransform';
- 9 if ( transform in _elementStyle ) return vendors[i].substr(0, vendors[i].length-1);
- 10 }
- 11
- 12 return false;
- 13 })();
- 14
- 15 function _prefixStyle (style) {
- 16 if ( _vendor === false ) return false;
- 17 if ( _vendor === '' ) return style;
- 18 return _vendor + style.charAt(0).toUpperCase() + style.substr(1);
- 19 }
① 动态创建标签样式——_elementStyle
② 检测样式支持度,并且返回需要的前缀
③ 获取验证结果,比如在chrome下变会返回webkit-XXX
当然,这里要加前缀的样式,一般都与CSS3有关,而下面就会遇到是transform
getTime
- me.getTime = Date.now || function getTime () { return new Date().getTime(); };
- //获取当前时间戳
extend
最最简单的扩展对象的方法
- 1 me.extend = function (target, obj) {
- 2 for ( var i in obj ) {
- 3 target[i] = obj[i];
- 4 }
- 5 };
addEvent/removeEvent
事件注册相关,我在想,若是使用了zepto这个代码量会减少点么?
- 1 me.addEvent = function (el, type, fn, capture) {
- 2 el.addEventListener(type, fn, !!capture);
- 3 };
- 4
- 5 me.removeEvent = function (el, type, fn, capture) {
- 6 el.removeEventListener(type, fn, !!capture);
- 7 };
momentum
这个方法比较重要,用于计算动画参数,会根据这个计算结果而决定动画运动效果,其实我们昨天的demo也用到了类似的东西
- 1 me.momentum = function (current, start, time, lowerMargin, wrapperSize) {
- 2 var distance = current - start,
- 3 speed = Math.abs(distance) / time,
- 4 destination,
- 5 duration,
- 6 deceleration = 0.0006;
- 7
- 8 destination = current + ( speed * speed ) / ( 2 * deceleration ) * ( distance < 0 ? -1 : 1 );
- 9 duration = speed / deceleration;
- 10
- 11 if ( destination < lowerMargin ) {
- 12 destination = wrapperSize ? lowerMargin - ( wrapperSize / 2.5 * ( speed / 8 ) ) : lowerMargin;
- 13 distance = Math.abs(destination - current);
- 14 duration = distance / speed;
- 15 } else if ( destination > 0 ) {
- 16 destination = wrapperSize ? wrapperSize / 2.5 * ( speed / 8 ) : 0;
- 17 distance = Math.abs(current) + destination;
- 18 duration = distance / speed;
- 19 }
- 20
- 21 return {
- 22 destination: Math.round(destination),
- 23 duration: duration
- 24 };
- 25 };
我们来做一点解释,首先看看我们的参数:
① 这个方法应该是在touchend时候使用,第一个参数为当前鼠标的位置
② 第二个参数是touchstart时候记录的坐标位置
③ 第三个参数为时间参数,便是开始触屏到离开时候所用时间(touchstart到touchend)
PS:这里我们其实可以做一个猜测了,我们有一次触屏的时间与距离,自然可以根据动力加速度计算出此次应该运动的时间与距离
④ 第四个参数是干神马的还不太明确,应该是控制边界位置的,这个就决定了我们不能无限制的拖动wrapper
⑤ 第五个参数为容器的高度
然后我们来以此读一读这里的代码:
① 得出此次拉动的距离distance/然后计算出这次拖动的速度(PS:个人觉得这里操作很不错,我没有想到)
② 然后定义了一些其它参数,deceleration这个用于计算速度/距离的参数,然后两个就是要返回的距离以及时间了
PS:我想说他这里的计算最终位置的函数应该是物理里面的一个计算摩擦参数的公式,尼玛是什么我真的不知道了,还有平方来着......
③ 这里还有一个关键点就是distance有可能是负值,这个会决定向上还是向下运动
④ 一般情况这里就结束来了,然后下面if里面一大段计算是用于处理运动轨迹超出时候的距离与速度重新计算(反弹效果)
好了,这个函数比较关键,他主要返回了最后要去到的位置,已经到这个位置的时间,里面具体的实现我们暂时不关系,后面这个必须理一理
检测与初始化
接下来做了一大段能力检测,比如:
① 是否支持CSS3动画相关(transform、transition)
② 是否支持touch事件
然后做了一些简单的初始化操作,这里新增了一个style对象,为他赋予了CSS动画相关的属性
③ 接下来是一些简单的样式操作,这样有个函数需要注意,他可以获取一个元素真正的位置信息
- 1 me.offset = function (el) {
- 2 var left = -el.offsetLeft,
- 3 top = -el.offsetTop;
- 4
- 5 // jshint -W084
- 6 while (el = el.offsetParent) {
- 7 left -= el.offsetLeft;
- 8 top -= el.offsetTop;
- 9 }
- 10 // jshint +W084
- 11
- 12 return {
- 13 left: left,
- 14 top: top
- 15 };
- 16 };

- 1 me.extend(me.ease = {}, {
- 2 quadratic: {
- 3 style: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)',
- 4 fn: function (k) {
- 5 return k * ( 2 - k );
- 6 }
- 7 },
- 8 circular: {
- 9 style: 'cubic-bezier(0.1, 0.57, 0.1, 1)', // Not properly "circular" but this looks better, it should be (0.075, 0.82, 0.165, 1)
- 10 fn: function (k) {
- 11 return Math.sqrt( 1 - ( --k * k ) );
- 12 }
- 13 },
- 14 back: {
- 15 style: 'cubic-bezier(0.175, 0.885, 0.32, 1.275)',
- 16 fn: function (k) {
- 17 var b = 4;
- 18 return ( k = k - 1 ) * k * ( ( b + 1 ) * k + b ) + 1;
- 19 }
- 20 },
- 21 bounce: {
- 22 style: '',
- 23 fn: function (k) {
- 24 if ( ( k /= 1 ) < ( 1 / 2.75 ) ) {
- 25 return 7.5625 * k * k;
- 26 } else if ( k < ( 2 / 2.75 ) ) {
- 27 return 7.5625 * ( k -= ( 1.5 / 2.75 ) ) * k + 0.75;
- 28 } else if ( k < ( 2.5 / 2.75 ) ) {
- 29 return 7.5625 * ( k -= ( 2.25 / 2.75 ) ) * k + 0.9375;
- 30 } else {
- 31 return 7.5625 * ( k -= ( 2.625 / 2.75 ) ) * k + 0.984375;
- 32 }
- 33 }
- 34 },
- 35 elastic: {
- 36 style: '',
- 37 fn: function (k) {
- 38 var f = 0.22,
- 39 e = 0.4;
- 40
- 41 if ( k === 0 ) { return 0; }
- 42 if ( k == 1 ) { return 1; }
- 43
- 44 return ( e * Math.pow( 2, - 10 * k ) * Math.sin( ( k - f / 4 ) * ( 2 * Math.PI ) / f ) + 1 );
- 45 }
- 46 }
- 47 });
这里定义了动画曲线供我们选取,我一般使用linear......
PS:这个地方的代码,不明觉厉!!!
自定义点击事件
- 1 me.tap = function (e, eventName) {
- 2 var ev = document.createEvent('Event');
- 3 ev.initEvent(eventName, true, true);
- 4 ev.pageX = e.pageX;
- 5 ev.pageY = e.pageY;
- 6 e.target.dispatchEvent(ev);
- 7 };
- 8
- 9 me.click = function (e) {
- 10 var target = e.target,
- 11 ev;
- 12
- 13 if (target.tagName != 'SELECT' && target.tagName != 'INPUT' && target.tagName != 'TEXTAREA') {
- 14 ev = document.createEvent('MouseEvents');
- 15 ev.initMouseEvent('click', true, true, e.view, 1,
- 16 target.screenX, target.screenY, target.clientX, target.clientY,
- 17 e.ctrlKey, e.altKey, e.shiftKey, e.metaKey,
- 18 0, null);
- 19
- 20 ev._constructed = true;
- 21 target.dispatchEvent(ev);
- 22 }
- 23 };
iScroll这里干了一件坏事,自己定义了tap以及click,意思是他可以触发绑定到dom上的tap或者click事件
然后整个util便结束了,其中momentum方法很是关键,接下来我们跟着程序流程走了
构造函数
构造函数是iScroll的入口,我们来详细读一读:
wrapper/scroller
为我们的外层结构,再里面一点就是拖动元素了,iscroll的处理是认为wrapper下第一个元素就是可拖动元素,我这里任务不妥......
- this.scroller = this.wrapper.children[0];
我们拖动的就是这个scroller了,我为什么说这样不妥呢?因为我如果现在又一个弹出层想使用iScroll的话,若是我弹出层有了wrapper了,我想自己往里面装DOM
而我的DOM搞不好有几个兄弟节点,这个时候我肯定不想自己再包裹一层的,所以iScroll这里的scroller我觉得系统构建比较合理(当然这只是个人认为)
下面还缓存了下当前scroll元素的style
- this.scrollerStyle = this.scroller.style;
初始化参数
iScroll当然自己会初始化一些默认属性了:
- 1 this.options = {
- 2
- 3 resizeIndicator: true,
- 4
- 5 mouseWheelSpeed: 20,
- 6
- 7 snapThreshold: 0.334,
- 8
- 9 // INSERT POINT: OPTIONS
- 10
- 11 startX: 0,
- 12 startY: 0,
- 13 scrollY: true,
- 14 directionLockThreshold: 5,
- 15 momentum: true,
- 16
- 17 bounce: true,
- 18 bounceTime: 600,
- 19 bounceEasing: '',
- 20
- 21 preventDefault: true,
- 22 preventDefaultException: { tagName: /^(INPUT|TEXTAREA|BUTTON|SELECT)$/ },
- 23
- 24 HWCompositing: true,
- 25 useTransition: true,
- 26 useTransform: true
- 27 };
若是我们传了相关属性会被复写的(这里上面定义了extend,却没有使用):
- 1 for ( var i in options ) {
- 2 this.options[i] = options[i];
- 3 }
能力检测
然后下面一大片结果基本做了一些能力检测的功能,然后将检测结果保存,因为我暂时只关心纵向滑动,所以一些地方便不予关心了
- 1 this.x = 0;
- 2 this.y = 0;
- 3 this.directionX = 0;
- 4 this.directionY = 0;
- 5 this._events = {};
这一坨东西还是要关注的,方向和初始值
初始化_init
上面一些默认属性定义结束便进入真正的初始化阶段,
- 1 _init: function () {
- 2 this._initEvents();
- 3
- 4 if ( this.options.scrollbars || this.options.indicators ) {
- 5 this._initIndicators();
- 6 }
- 7
- 8 if ( this.options.mouseWheel ) {
- 9 this._initWheel();
- 10 }
- 11
- 12 if ( this.options.snap ) {
- 13 this._initSnap();
- 14 }
- 15
- 16 if ( this.options.keyBindings ) {
- 17 this._initKeys();
- 18 }
- 19 // INSERT POINT: _init
- 20 },
代码很清晰,我现在的需求关注_initEvents与_initIndicators就好了,其它暂时可以不管,关键点便是事件绑定了
_initEvents
- 1 _initEvents: function (remove) {
- 2 var eventType = remove ? utils.removeEvent : utils.addEvent,
- 3 target = this.options.bindToWrapper ? this.wrapper : window;
- 4
- 5 eventType(window, 'orientationchange', this);
- 6 eventType(window, 'resize', this);
- 7
- 8 if ( this.options.click ) {
- 9 eventType(this.wrapper, 'click', this, true);
- 10 }
- 11
- 12 if ( !this.options.disableMouse ) {
- 13 eventType(this.wrapper, 'mousedown', this);
- 14 eventType(target, 'mousemove', this);
- 15 eventType(target, 'mousecancel', this);
- 16 eventType(target, 'mouseup', this);
- 17 }
- 18
- 19 if ( utils.hasPointer && !this.options.disablePointer ) {
- 20 eventType(this.wrapper, 'MSPointerDown', this);
- 21 eventType(target, 'MSPointerMove', this);
- 22 eventType(target, 'MSPointerCancel', this);
- 23 eventType(target, 'MSPointerUp', this);
- 24 }
- 25
- 26 if ( utils.hasTouch && !this.options.disableTouch ) {
- 27 eventType(this.wrapper, 'touchstart', this);
- 28 eventType(target, 'touchmove', this);
- 29 eventType(target, 'touchcancel', this);
- 30 eventType(target, 'touchend', this);
- 31 }
- 32
- 33 eventType(this.scroller, 'transitionend', this);
- 34 eventType(this.scroller, 'webkitTransitionEnd', this);
- 35 eventType(this.scroller, 'oTransitionEnd', this);
- 36 eventType(this.scroller, 'MSTransitionEnd', this);
- 37 },
这段代码,是整个iScroll的核心,整个入口函数其实在这里,我们暂时的关注点又在这里:
- 1 if ( utils.hasTouch && !this.options.disableTouch ) {
- 2 eventType(this.wrapper, 'touchstart', this);
- 3 eventType(target, 'touchmove', this);
- 4 eventType(target, 'touchcancel', this);
- 5 eventType(target, 'touchend', this);
- 6 }
PS:这里有一点让我比较疑惑的就是这里传递进去的fn是一个对象,而不是函数,看来我事件机制一块仍然不到家:
然后进入我们的touch事件,反正现在touchstart便会进入我们的start回调函数
touchStart
- 1 _start: function (e) {
- 2 // React to left mouse button only
- 3 if ( utils.eventType[e.type] != 1 ) {
- 4 if ( e.button !== 0 ) {
- 5 return;
- 6 }
- 7 }
- 8
- 9 if ( !this.enabled || (this.initiated && utils.eventType[e.type] !== this.initiated) ) {
- 10 return;
- 11 }
- 12
- 13 if ( this.options.preventDefault && !utils.isBadAndroid && !utils.preventDefaultException(e.target, this.options.preventDefaultException) ) {
- 14 e.preventDefault();
- 15 }
- 16
- 17 var point = e.touches ? e.touches[0] : e,
- 18 pos;
- 19
- 20 this.initiated = utils.eventType[e.type];
- 21 this.moved = false;
- 22 this.distX = 0;
- 23 this.distY = 0;
- 24 this.directionX = 0;
- 25 this.directionY = 0;
- 26 this.directionLocked = 0;
- 27
- 28 this._transitionTime();
- 29
- 30 this.startTime = utils.getTime();
- 31
- 32 if ( this.options.useTransition && this.isInTransition ) {
- 33 this.isInTransition = false;
- 34 pos = this.getComputedPosition();
- 35 this._translate(Math.round(pos.x), Math.round(pos.y));
- 36 this._execEvent('scrollEnd');
- 37 } else if ( !this.options.useTransition && this.isAnimating ) {
- 38 this.isAnimating = false;
- 39 this._execEvent('scrollEnd');
- 40 }
- 41
- 42 this.startX = this.x;
- 43 this.startY = this.y;
- 44 this.absStartX = this.x;
- 45 this.absStartY = this.y;
- 46 this.pointX = point.pageX;
- 47 this.pointY = point.pageY;
- 48
- 49 this._execEvent('beforeScrollStart');
- 50 }
前面做了一系列的兼容性处理,然后记录了一些数据便结束了
结语
今天有点晚了,我也暂时结束了,明天还要上班呢,下次详细研究下touch事件的几个阶段干的事情以及滚动条的实现
【iScroll源码学习01】准备阶段 - 叶小钗的更多相关文章
- 【iScroll源码学习01】准备阶段
前言 我们昨天初步了解了为什么会出现iScroll:[SPA]移动站点APP化研究之上中下页面的iScroll化(上),然后简单的写了一个demo来模拟iScroll,其中了解到了以下知识点: ① v ...
- 【iScroll源码学习02】分解iScroll三个核心事件点
前言 最近两天看到很多的总结性发言,我想想今年好像我的变化挺大的,是不是该晚上来水一发呢?嗯,决定了,晚上来水一发! 上周六,我们简单模拟了下iScroll的实现,周日我们开始了学习iScroll的源 ...
- 【iScroll源码学习04】分离IScroll核心
前言 最近几天我们前前后后基本将iScroll源码学的七七八八了,文章中未涉及的各位就要自己去看了 1. [iScroll源码学习03]iScroll事件机制与滚动条的实现 2. [iScroll源码 ...
- 【iScroll源码学习03】iScroll事件机制与滚动条的实现
前言 想不到又到周末了,周末的时间要抓紧学习才行,前几天我们学习了iScroll几点基础知识: 1. [iScroll源码学习02]分解iScroll三个核心事件点 2. [iScroll源码学习01 ...
- 【iScroll源码学习00】模拟iScroll
前言 相信对移动端有了解的朋友对iScroll这个库非常熟悉吧,今天我们就来说下我们移动页面的iScroll化 iScroll是我们必学框架之一,我们这次先根据iScroll功能自己实现其功能,然后再 ...
- iscroll源码学习(1)
iscroll是移端端开发的两大利器之一(另一个是fastclick),为了将它整合的avalon,需要对它认真学习一番.下面是我的笔记. 第一天看的是它的工具类util.js //用于做函数节流 v ...
- 【requireJS源码学习01】了解整个requireJS的结构
前言 现在工作中基本离不开requireJS这种模块管理工具了,之前一直在用,但是对其原理不甚熟悉,整两天我们来试着学习其源码,而后在探寻其背后的AMD思想吧 于是今天的目标是熟悉requireJS整 ...
- VUE 源码学习01 源码入口
VUE[version:2.4.1] Vue项目做了不少,最近在学习设计模式与Vue源码,记录一下自己的脚印!共勉!注:此处源码学习方式为先了解其大模块,从宏观再去到微观学习,以免一开始就研究细节然后 ...
- jQuery 源码学习 - 01 - 简洁的 $('...')
首先贴上学习参考资料:[深入浅出jQuery]源码浅析--整体架构,备用地址:chokcoco/jQuery-. jQuery 库,js 开发的一个里程碑,它的出现,让网页开发者们告别荒蛮的上古时代, ...
随机推荐
- lucene索引合并与增量索引
利用 Lucene,在创建索引的工程中你可以充分利用机器的硬件资源来提高索引的效率.当你需要索引大量的文件时,你会注意到索引过程的瓶颈是在往磁盘上写索引文件的过程中.为了解决这个问题, Lucene ...
- PAT (Advanced Level) 1099. Build A Binary Search Tree (30)
预处理每个节点左子树有多少个点. 然后确定值得时候递归下去就可以了. #include<cstdio> #include<cstring> #include<cmath& ...
- Linux中防火墙centos
一般的防火墙用下面这些简单的配置都能达到目的 1) 重启后生效 开启: chkconfig iptables on 关闭: chkconfig iptables off 2) 即时生效,重启后失效 开 ...
- 为什么做Web开发要选择PHP
大部分互联网公司做WEb开发都选择PHP,PHP的优势在哪?你应该知道的 以前偶尔被人问到,为什么你(和大部分互联网公司)做Web开发要选择PHP, PHP有什么好处.简单的回答便是“PHP简单,开发 ...
- Linux SCP命令复制传输文件的用法
SCP命令是用户通过网络将一台Linux服务器的文件复制到另一台Linux服务器,方法如下: 一:从本地复制到远程 复制文件: 命令格式: scp local_file remote_username ...
- SystemClock.sleep和Thread.sleep的区别
在Java中我们处理线程同步问题时,处理延迟可能会使用Thread类的sleep方法,这里抛开concurrent类的一些方法,其实 Android平台还提供了一个SystemClock.sleep方 ...
- 理解用requireJs 来实现javascript的模块化加载
这是我看到的一片关于requirejs的初学者的文章,写的不错,下面结合自己的理解记录一下: 原文:http://www.sitepoint.com/understanding-requirejs-f ...
- script 两则
script1: PATH=/usr/local/bin:/usr/bin:$PATH:. . $HOME/utility/macro/macro.env OVO_DIR=/tmp LOGFILE=$ ...
- nullable,kindof,泛型新特性
文章来自: http://blog.csdn.net/majiakun1/article/details/46530245 Overview 自 WWDC 2015 推出和开源 Swift 2.0 后 ...
- FZU Problem 2150 Fire Game(bfs)
这个题真要好好说一下了,比赛的时候怎么过都过不了,压点总是出错(vis应该初始化为inf,但是我初始化成了-1....),wa了n次,后来想到完全可以避免这个问题,只要入队列的时候判断一下就行了. 由 ...