JavaScript开源:AlloyTouch - 全屏滚动插件,30秒搞定顺滑H5页

pr5656 8年前
   <h2>使用姿势</h2>    <p>在设计全屏滚动插件的时候,希望开发者几乎:</p>    <ul>     <li>不用写任何脚本快速生成精致H5</li>     <li>支持PC滚轮和移动触摸</li>     <li>酷炫的转场动效</li>     <li>灵活的时间轴管理</li>     <li>一切皆可配置</li>    </ul>    <p>但是不写脚本肯定没有灵活性咯?!不是的。这里不仅仅可以通过在HTML配置一些参数,还可通过插件的回调函数进行一些逻辑注入。就拿上面大家扫码看到的例子的 <strong>部分HTML</strong> 来分析下AlloyTouch.FullPage的使用姿势:</p>    <pre>  <code class="language-javascript"><div id="fullpage">          <div>              <div>                  <div class="animated" data-show="bounceInLeft" data-hide="bounceOutLeft">AlloyTouch Introduction</div>                  <div class="animated" data-delay="500" data-show="bounceInUp" data-hide="zoomOut"><img src="asset/alloytouch.png"></div>                  <div class="animated" data-delay="1200" data-show="bounceIn" data-hide="bounceOut">By AlloyTeam</div>              </div>          </div>                    <div>              <div>                  <div class="animated"  data-delay="100" data-show="flipInY" data-hide="flipOutY" >Powerful Features</div>                  <div class="animated"  data-delay="400" data-show="zoomIn" data-hide="zoomOut"><img src="asset/power.png"></div>              </div>          </div>          ...          ...          ...   </div></code></pre>    <p>注意,上面只是部分HTML,而且我已经把一些和插件配置无关的HTML去掉了。下面一一进行分析:</p>    <ul>     <li>class="animated"符合 animate.css 的约定,加上了这个class代表会有动画。</li>     <li>data-delay代表滚到该页面之后,被标记的DOM元素要等待多久才开始播放动画。如果开发者不标记的话默认值是0。</li>     <li>data-show代表被标记的DOM元素显示的动画类型</li>     <li>data-hide代表被标记的DOM元素隐藏的动画类型(这个通常用户看不到,但是为了show的时候平滑,一般设置为与data-show的相反的类型)</li>    </ul>    <p>就这么多,配置就这么多,配置就这么多!!够简单把!!</p>    <p>当然你需要在js里面初始化一下:</p>    <pre>  <code class="language-javascript">new AlloyTouch.FullPage("#fullpage",{          animationEnd:function () {                    },          leavePage: function (index) {              console.log("leave"+index)          },          beginToPage: function (index) {              console.log("to"+index);              pb.to(index / (this.length-1));          }      });</code></pre>    <ul>     <li>animationEnd是滚动结束之后的回调函数</li>     <li>leavePage是代表离开某个页面的回调函数</li>     <li>beginToPage代表打算去某个页面的回调函数</li>    </ul>    <p>上面的pb是用来设置nav或者progress的进度,这个可以先不用管。如果有需要的话,用户可以自己封装任意的进度条组件。</p>    <h2>原理分析</h2>    <p>这里主要抽取了AlloyTouch.FullPage的核心代码进行分析:</p>    <pre>  <code class="language-javascript">new AlloyTouch({      touch: this.parent,      target: this.parent,      property: "translateY",      min: (1 - this.length) * this.stepHeight,      max: 0,      step: this.stepHeight,      inertia: false,      bindSelf : true,      touchEnd: function (evt, v, index) {          var step_v = index * this.step * -1;          var dx = v - step_v;            if (v < this.min) {              this.to(this.min);          } else if (v > this.max) {              this.to(this.max);          } else if (Math.abs(dx) < 30) {              this.to(step_v);          }else if (dx > 0) {              self.prev();          } else {              self.next();          }          return false;      },      animationEnd: function () {          option.animationEnd.apply(this,arguments);          self.moving = false;      }  });</code></pre>    <ul>     <li>这里触摸和运动的Dom都是fullpage的dom,也就是上面的this.parent</li>     <li>因为是上下滚动,所以运动的属性是translateY</li>     <li>min可以通过window.innerHeight和总共的页数推算出来,this.stepHeight就是window.innerHeight</li>     <li>max显然就是0</li>     <li>step显然就是window.innerHeight,也就是this.stepHeight</li>     <li>inertia: false代表把惯性运动禁止掉,也就是用户松手和不会惯性滚动</li>     <li>bindSelf是意思是touchmove和touchend以及touchcancel都绑定在this.parent自己,而非window下。不设置bindSelf的话touchmove和touchend以及touchcancel都绑定在window下。</li>    </ul>    <p>这里需要特别详细说下,这个bindSelf配置非常有用,比如很典型的应用场景就是解决AlloyTouch嵌套AlloyTouch的问题。比如你上面扫码看到的例子里面,嵌套了AlloyTouch的Demo如下所示:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/b92a19d2abab0a2f549c07ed77fc7ed3.png"></p>    <p>这里其实是嵌套的滚动。滚动里面的会导致外面的也滚动?怎么解决?里面的滚动必须加上bindSelf并且阻止冒泡:</p>    <p>且看内部滚动的详细代码:</p>    <pre>  <code class="language-javascript">var scroller = document.querySelector("#scroller");  Transform(scroller,true);    new AlloyTouch({      touch:"#demo0",      target: scroller,       property: "translateY",        min:250-2000,      max: 0 ,      touchStart:function(evt){          evt.stopPropagation();      },      touchMove:function(evt){          evt.stopPropagation();      },      bindSelf:true  })</code></pre>    <p>这样的话,嵌套的HTML里面的嵌套的AlloyTouch就不会向上冒泡了,也就是滚动里面的就不会触发外面的滚动。</p>    <p>继续分析FullPage源码:</p>    <p>touchEnd是用户手指离开屏幕之后的回调函数。里面有边界处理的逻辑:</p>    <ul>     <li>超出min和max都会对应的校正会min和max。</li>     <li>step校正,绝对值小于30px会复位</li>     <li>step校正,绝对值大于30px且大于0会去上一页</li>     <li>step校正,绝对值大于30px且小于0会去下一页</li>     <li>return false代表不会去运行AlloyTouch松开手后的运动校正逻辑,这点很重要</li>    </ul>    <p>animationEnd就是运动结束之后的回调函数,会去执行用户从AlloyTouch.FullPage传递过来的animationEnd,并且把moving设置为false</p>    <p> </p>    <p> </p>    <p> </p>