zoukankan      html  css  js  c++  java
  • 记:使用IScroll.js 开发picker日历组件遇到的问题及经验总结

    IScroll中文文档

    第一个问题: 边界留白

      

      就是这种,上边界(最小),下边界(最大)有两个列表的位置是不能选择的。解决的办法是:

      

      在HTML中,添加空白节点就行了。

    第二个问题:初始化之后的滚动停止的事件的第二个参数问题。  

    var myScroll = new IScroll('#wrapper');
    myScroll.on('scrollEnd', function(){
        //这里一定不要写成es6箭头函数
        //要执行的代码
        //这个函数没有参数
    });

    (1) 第二的个参数,是个函数。它没有参数,而且不要写成,不要写成,不要写成箭头的形式。因为这函数里面的this,是绑定的一些有用信息,比如:this.y是当前滚动的距离等。还有哪些信息可以看 文档中的 滚动条信息 这一栏。如果写成ES6的形式,那this指向就变了,这样就获取不了所需的信息。

    (2) 第二个参数是没有形参的。即没有任何可使用的参数。

    第三个问题:定义了snap选项,但是滚动有偏差

      开发的日历选择组件picker是使用rem单位自适应的,虽然在配置项中 有个options.snap,官方说可以对齐到固定的位置和元素,但是在使用自适应单位的情况中,这个配置并没有展现出真正的效果,滚动的时候一定会出现偏差。

      那怎么解决这个自适应的问题呢?由于是在滚动结束之后,位置才出现的偏差。那么我就在滚动结束之后立马调用修正位置的函数就行了。

      我是在vue中使用的。所以定义下面的函数,因为有 年,月,日,时四个滚动项。所以需要判断是哪一个正在滚动

    fixPos: function(target,num) {
        var step = Math.abs(Math.round(target.y / this.itemHeight));
        var maxYearLen = this.yearArr.length;
        var maxMonthLen = this.monthArr.length;
        var maxDayLen = this.dayArr.length;
        var maxHourLen = this.hourArr.length;
        switch(num){
            case 0:
                step = step > maxYearLen ? maxYearLen - 1 : step;
                break;
            case 1:
                step = step > maxMonthLen ? maxMonthLen - 1 : step;
                break;
            case 2:
                step = step > maxDayLen ? maxDayLen - 1 : step;
                break;
            case 3:
                step = step > maxHourLen ? maxHourLen - 1 : step;
                break;
        }
        var fixPos = step * this.itemHeight;//重新计算较为精确的位置
        target.y = fixPos;//重置原来的滚动距离
        this.selectArr[num] = step;//这是保存每个列表滚动的索引值
        target.scrollTo(0, -fixPos);//这是滚动到修正后的位置
    },

    (1) 大致的思路就是:首先用当前滚动的距离,来除以滚动内容中,每个列表的高度。然后取最近似的值,就是当前应该滚动的列表的个数。

    (2) 如果出现突然滚动到最底部,这时候需要滚动的个数大于了滚动内容的最大列表个数,那么就纠正一下个数为最大列表数 - 1。

    (3) 然后设置较为精确的滚动距离。再滚动到指定的位置。

    (4) this.itemHeight是在created生命周期的时候就声明的 this.itemHeight = (document.body.offsetWidth / 750) * 100 * 0.8;  相当于在375px宽度下,每个列表就是40px的高度。在iPhone5 320px下,就是34.133334了。

      调用的时候: 

    var yearScroll = new IScroll('#calendarYear');
    var that = this;
    yearScroll.on('scrollEnd', function() {
        that.fixPos(this, 0);
    })

      

    第四个问题:使用自适应单位时最大滚动距离不准确

      这个问题和第二个问题类似,解决的方法:

    fixMaxScrollY: function(target, num) {
        var yearLen = this.yearArr.length - 1;
        var monthLen = this.monthArr.length - 1;
        var dayLen = this.dayArr.length - 1;
        var hourLen = this.hourArr.length - 1;
        switch(num) {
            case 0:
                target.maxScrollY = -(Math.round(yearLen * this.itemHeight));
                break;
            case 1:
                target.maxScrollY = -(Math.round(monthLen * this.itemHeight));
                break;
            case 2:
                target.maxScrollY = -(Math.round(dayLen * this.itemHeight));
                break;
            case 3:
                target.maxScrollY = -(Math.round(hourLen * this.itemHeight));
                break;
        }
    },

    (1)  实例化后的滚动对象,有个最大滚动值maxScrollY,主要也是根据滚动内容的列表长度来重置最大滚动距离

    (2)  因为有四个滚动的内容项,所以需要传入当前是第几个滚动的内容。

      调用的时候:

    var yearScroll = new IScroll('#calendarYear');
    this.fixMaxScrollY(yearScroll, 0);

    第五个问题: 日历组件的内容是在点击某个按钮之后再触发显示的,最初是隐藏。但就是这个原因,导致显示出来的内容滚动不了

      解决的办法是:使用 xxx.refresh() 刷新函数。这个函数具体的说明可以看文档中 刷新 这个选项内容

      在控制组件显示的函数中,调用刷新的方法。

    this.$nextTick(function(){
        this.scrollTarget[0].refresh();
        this.scrollTarget[1].refresh();
        this.scrollTarget[2].refresh();
        this.scrollTarget[3].refresh();
        //如果默认隐藏,则必须修复滚动的位置
        this.scrollTarget[0].scrollTo(0, -this.itemHeight * this.selectArr[0]);
        this.scrollTarget[1].scrollTo(0, -this.itemHeight * this.selectArr[1]);
        this.scrollTarget[2].scrollTo(0, -this.itemHeight * this.selectArr[2]);
        this.scrollTarget[3].scrollTo(0, -this.itemHeight * this.selectArr[3]);
    })

    (1) scrollTarget 是初始化滚动实例之后,保存的滚动实例。因为多次会用到。

    (2) 因为有年,月,日,时四个滚动内容,所以要刷新四个滚动器。

    (3) 如果日历有最初的滚动位置,那么也会出现不能跳到指定的位置的问题。所以,也需要初始化最初始的位置。

    (4) selectArr 是滚动器滚动的索引值。比如我月份是1月到12月,当前滚动到了6月,那么此时selectArr[1] 就是5 。

    (5) 官方是推荐用setTimeout来使用刷新,但是我使用的是vue来开发的,所以,这里用vm.$nextTick()来代替setTimeout。

    第六个问题: 日历组件复用时,只能初始化滚动第一个日历组件,而且第一个日历组件滚动还是有问题。

      这个问题产生的原因很简单:因为 IScroll 在初始化实例的时候, var myScroll = new IScroll('.wrapper');  它这个css选择器使用的是querySelector 而不是 querySelectorAll,所以iScroll只会作用到选择器选中元素的第一个。如果你需要对多个对象使用iScroll,你需要构建自己的循环机制。这是官方的说法。那么怎样建立循环机制呢?难道我要在初始化的时候还要循环去 new IScroll(xxx)创建实例吗?

      其实没必要。只需要改一改源码就行了。

      我使用的是 iscroll-lite 这个版本。这里面 在定义 IScroll 这个函数的时候有这段代码

    this.wrapper = typeof el == 'string' ? document.querySelector(el) : el;

      它每次初始化时,只选择了 el  滚动对象的第一个元素,那么,我只需要传入当前是第几个日历组件,再改成querySelectorAll就行了。即:

    this.wrapper = typeof el == 'string' ? document.querySelectorAll(el)[childIndex] : el;

      然后在这个定义的 IScroll 函数的参数中,再增加一个参数,表示第几个元素。

      然后在初始化滚动实例的时候:

    var options = {
        snap: '.calendar-scroll-item', //对齐的位置,相当于自动纠正每次移动的距离
        //scrollbars: true,//是否显示滚动条
    }
    //初始化滚动
    var yearScroll = new IScroll('.calendar-scroll>.calendarYear', options , this.curIndex);

      当然这个时候,css选择器就不要用 id 了。

      然后在 组件的 prop 里面添加一个属性。

    curIndex:{
        type:Number,
        default:0
    }

    (1) 默认只使用一个组件,即不传这个prop 的话就是默认初始化第一个组件的滚动内容。

      使用组件的时候:引入,注册等步骤就省略了

    <calendar :cur-index='0'/>
    <calendar :cur-index='1'/>
    <calendar :cur-index='2'/>

       这样不管使用多少个,都能正常初始化滚动了。而且互不影响 。注意,如果传的是数字,需要v-bind 告诉vue这不是字符串,是表达式。不然传过去的是字符串

  • 相关阅读:
    Android开发 ViewConfiguration View的配置信息类
    Android 开发 倒计时功能 转载
    Android 开发 关于7.0 FileUriExposedException异常 详解
    Android 开发 实现文本搜索功能
    Android 开发 Activity里获取View的宽度和高度 转载
    Android 开发 存储目录的详解
    Android 开发 Fresco框架点击小图显示全屏大图实现 ZoomableDraweeView
    Android 开发 将window变暗
    Android 开发 DisplayMetrics获取Android设备的屏幕高宽与其他信息
    Android 开发 DP、PX、SP转换详解
  • 原文地址:https://www.cnblogs.com/zjjDaily/p/11077092.html
Copyright © 2011-2022 走看看