zoukankan      html  css  js  c++  java
  • iscroll源码初涉

      最近尝试做web app时候,用上了神器iScroll,鉴于功力尚浅,并没有完全用好神器,所以今天特意来认真学习!

      翻开官网,目前的版本是5,但是相关的文章并不多,具体的文件版本是:

    • iscroll.js 常规版本
    • iscroll-lite.js 阉割版本,如果只需要滑动功能,推荐这个,体积很小。不支持snap,scrollbars,mouse wheel,key bindings。
    • iscroll-probe.js 专门提供获取当前位置的功能,未来可能在常规版本中加入。
    • iscroll-zoom.js 添加zooming功能
    • iscroll-infinlte.js 由于过长的列表滚动对手机设备硬件要求较高,所以此版本利用缓存机制来达到这效果。

      项目里面用的是iscroll-probe这个版本,具体原因是需要使用定位功能,但是今天学习,还是选软柿子(iscroll-lite)来捏吧。

      进门第一段代码:

    //请求动画帧
    var rAF = window.requestAnimationFrame   ||
        window.webkitRequestAnimationFrame   ||
        window.mozRequestAnimationFrame      ||
        window.oRequestAnimationFrame        ||
        window.msRequestAnimationFrame       ||
        function (callback) { window.setTimeout(callback, 1000 / 60); };
    /*
    显示器16.7ms刷新间隔之前发生了其他绘制请求(setTimeout),导致所有帧丢失,setTimeout的定时器值推荐最小使用16.7ms的原因(16.7 = 1000 / 60, 即每秒60帧)
    requestAnimationFrame与setTimeout的不同在于,前者跟着浏览器重绘时间走,不存在后者丢帧的问题
    */

      

       完全不懂……于是马上找鑫爷的博客翻看才知这是一个js的动画接口----请求动画帧,requestAnimationFrame与setTimeout的不同在于,前者跟着浏览器重绘时间走,不存在后者丢帧的问题。《CSS3动画那么强,requestAnimationFrame还有毛线用?》。 

      大概初窥到iScroll的滑动效果的大门,继续往下看,结构非常清晰:util + iscroll + iscroll.prototype。

      util主要是封装了一些获取样式名称(前缀)的方法,事件绑定方法,动画缓动方法,样式操作方法,其中最重要的是 preventDefaultException , tap , click这三个方法。

    // 配合config里面的preventDefaultException属性,匹配到的element使用e.preventDefault()。
    // 默认preventDefaultException是 { tagName: /^(INPUT|TEXTAREA|BUTTON|SELECT)$/ }
    me.preventDefaultException = function (el, exceptions) {
        for ( var i in exceptions ) {
            if ( exceptions[i].test(el[i]) ) {
                return true;
            }
        }
        return false;
    };
    
    me.tap = function (e, eventName) {
        var ev = document.createEvent('Event');
        /**
        只有在新创建的 Event 对象被 Document 对象或 Element 对象的 dispatchEvent() 方法分派之前,才能调用 Event.initEvent() 方法        
        初始化新事件对象的属性
        */
        ev.initEvent(eventName, true, true);
        ev.pageX = e.pageX;
        ev.pageY = e.pageY;
        //事件触发器就是用来触发某个元素下的某个事件
        e.target.dispatchEvent(ev);
    };
    
    me.click = function (e) {
        var target = e.target,
            ev;
    //不是select/input/textarea就创建事件
    if ( !(/(SELECT|INPUT|TEXTAREA)/i).test(target.tagName) ) { ev = document.createEvent('MouseEvents'); ev.initMouseEvent('click', true, true, e.view, 1, target.screenX, target.screenY, target.clientX, target.clientY,e.ctrlKey, e.altKey, e.shiftKey, e.metaKey,0, null);    //作为是否需要perventDefault的标志   ev._constructed = true; target.dispatchEvent(ev); } };

       继续往下,就是iScroll的初始化操作,new iScroll的时候,会优先处理一些默认设置,其中有如下几点需要注意:

    1. eventPassthrough参数支持两种写法,一是boolean类型true / false , 二是string类型'vertical' / 'horizontal';
    2. eventPassthrough设为true时候,会自动转为'vertical',并且会设置scrollX为false,即水平滑动的时候,使用的是浏览器原生滑动;
    3. freeScroll只能与scrollX一起使用 {scrollX:true,freeScroll:true}

      最后就是

    // IScroll初始化鼠标/手势事件
    this._init();
    // 设置可滑动值
    this.refresh();
    // 定位到最顶最左
    this.scrollTo(this.options.startX, this.options.startY);
    // 代表“启用”的一个标志
    this.enable();

      此中最重要的是_init方法里面调用的_initEvents, 使用的是handleEvent。 利用这个特性可以把任意对象注册为事件处理程序,只要它拥有 handleEvent 方法。

    所以iScroll里面有一个handleEvent属性,利用element.addEventListener( 'transitionend', IScroll)的方式,来处理相关事件。

    IScroll.prototype = {
      handleEvent: function (e) {
          switch ( e.type ) {
                case 'touchstart':
                    ......
                    this._start(e);
                    break;
                case 'touchmove':
                    ......
                    this._move(e);
                    break;
                case 'touchend':
                    ......
                    this._end(e);
                    break;
                case 'orientationchange':
                case 'resize':
                    this._resize();
                    break;
                case 'transitionend':
                    ......
                    this._transitionEnd(e);
                    break;
                case 'wheel':
                    ......
                    this._wheel(e);
                    break;
                case 'keydown':
                    this._key(e);
                    break;
                case 'click':
                    if ( !e._constructed ) {
                        e.preventDefault();
                        e.stopPropagation();
                    }
                    break;
            }
        }
    }    

         好了,iScroll的初始化以及事件处理已经差不多了,接下来就是事件处理程序,估计也是一些位置处理的东西了吧,继续:

    • _start(e)    具体作用是初始化一些位置信息;
    • _move(e)  移动过程更新位置信息,触发动态效果;
    • _end(e)     结束时根据是否需要缓动而作相应的缓动动作

      具体的可以查看我写的《iscroll-lite源码注释》,其实,看完源码,真的没什么很复杂的,但是有几点觉得有待商榷的:

    1. 对于_execEvent(eventType)的方法,应该再加上当前触发的event对象,_execEvent( eventType,event ),因为在执行的时候this._events[type][i].apply(this, [].slice.call(arguments, 1));会从第二个参数截取,加上event对象,有助于我们判断是在哪个元素上触发事件。
    2. off解绑事件,缺乏一次性解绑的方法,建议把解绑的方法修改如下:
      if ( index > -1 ) {
          this._events[type].splice(index, 1);
      }else{
          this._events[type].length = 0;
      }

      最后送上完整的参数设置:

    var options = {
        startX: 0,
        startY: 0,    
        //Y轴是否滑动
        scrollY: true,
        //X轴是否滑动
        scrollX: true,
        //是否自由滑动 x y都滑 , freeScroll只能与scrollX一起使用 {scrollX:true,freeScroll:true}
        freeScroll : false,
        //方向锁定阈值,比如用户点击屏幕后,x与y之间差距大于5px,判断用户的拖动意图,是x方向拖动还是y方向
        directionLockThreshold: 5,
        //是否有惯性缓冲动画
        momentum: true,
        //超出边界时候是否还能拖动
        bounce: true,
        //超出边界还原时间点
        bounceTime: 600,
        //超出边界返回的动画
        bounceEasing: '',
        //是否阻止默认滚动事件
        preventDefault: true,
        //当遇到表单元素则不阻止冒泡,而是弹出系统自带相应的输入控件
        preventDefaultException: { tagName: /^(INPUT|TEXTAREA|BUTTON|SELECT)$/ },
        //硬件合成 通过GPU做图形渲染
        HWCompositing: true,
        //使用transition
        useTransition: true,
        //使用transform
        useTransform: true,
        //穿透 是否不触发原生滑动
        eventPassthrough : false,
        //缓动函数 {string|function}
        bounceEasing : '',
        //resize时候隔60ms就执行refresh方法重新获取位置信息
        resizePolling : 60,
        //是否允许点击事件
        click : false,
        //模拟tap事件,并且触发addEventListener('tap')所指定的方法
        tap : 'tap',
        //匀减速变量
        deceleration : 0.0006,
        //事件是否绑定到wrapper元素上,否则大部分绑定到window
        bindToWrapper : false.
        //是否禁用鼠标
        disableMouse : false,
        //是否禁用win系统的pointer事件
        disablePointer : false,
        //是否禁用touch事件
        disableTouch : false
    };
  • 相关阅读:
    TextBox 只有下划线
    can't find web control library(web控件库)
    DropDownListSalesAC”有一个无效 SelectedValue,因为它不在项目列表中。
    IDE、SATA、SCSI、SAS、FC、SSD 硬盘类型
    如何打印1px表格
    CSS控制打印 分页
    Virtual Server could not open its emulated Ethernet switch driver. To fix this problem, reenable the Virtual Server Emulated Et
    Xml中SelectSingleNode方法中的xpath用法
    热带水果莫入冰箱?水果存放冰箱大法
    探索Asp.net的Postback机制
  • 原文地址:https://www.cnblogs.com/viccici/p/3878680.html
Copyright © 2011-2022 走看看