记:使用IScroll.js 开发picker日历组件遇到的问题及经验总结
第一个问题: 边界留白
就是这种,上边界(最小),下边界(最大)有两个列表的位置是不能选择的。解决的办法是:
在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这不是字符串,是表达式。不然传过去的是字符串
记:使用IScroll.js 开发picker日历组件遇到的问题及经验总结的更多相关文章
- 基于mxgraph.js开发的流程图组件
1.fabric.js 在决定使用mxgraph.js开发流程图之前,尝试过用fabric.js来开发,结果发现并没有想象中的那么简单,而且用户体验非常差,下面是体验地址:workFlow直到遇到一个 ...
- JS开发页面小组件:table组件
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...
- 日历组件 原生js
自己基于原生js编写的日历组件 git地址: https://github.com/lihefen/calendar.git demo : https://lihefen.github.io/cale ...
- 前端笔记之React(四)生命周期&Virtual DOM和Diff算法&日历组件开发
一.React生命周期 一个组件从出生到消亡,在各个阶段React提供给我们调用的接口,就是生命周期. 生命周期这个东西,必须有项目,才知道他们干嘛的. 1.1 Mouting阶段[装载过程] 这个阶 ...
- vue-calendar 基于 vue 2.0 开发的轻量,高性能日历组件
vue-calendar-component 基于 vue 2.0 开发的轻量,高性能日历组件 占用内存小,性能好,样式好看,可扩展性强 原生 js 开发,没引入第三方库 Why Github 上很多 ...
- calendar.js(日历组件封装)
最近一直闲来无事,便寻思着做一下自己的个人项目,也想说能使用现在比较流行的一些mvvm框架来做,于是就选用了这样的一个技术栈vue2.0+vue-router+vuex+webpack来做,做得也是多 ...
- vue2.0项目 calendar.js(日历组件封装)
最近一直闲来无事,便寻思着做一下自己的个人项目,也想说能使用现在比较流行的一些mvvm框架来做,于是就选用了这样的一个技术栈vue2.0+vue-router+vuex+webpack来做,做得也是多 ...
- [js开源组件开发]js文本框计数组件
js文本框计数组件 先上效果图: 样式可以自行调整 ,它的功能提供文本框的实时计数,并作出对应的操作,比如现在超出了,点击下面的按钮后,文本框会闪动两下,阻止提交.具体例子可以点击demo:http: ...
- 跨平台移动开发 手机上使用Iscroll.Js的Banner
二话不说,直接上图,看效果 需要使用Iscroll <script src="content/scripts/iscroll.js"></script> 示 ...
随机推荐
- 面试官问我,为什么老司机建议MySQL列属性尽量用 NOT NULL ?
本文阅读时间大约6分钟. 其实写这篇文章,也是来自一个知识星球读者的提问,他在二面的过程中被问到了,由于他简历中写道有 MySQL 调优经验,但这个问题没有回答好,二面被刷了. 其实我们刚学习 C 语 ...
- ML-逻辑回归推导
认识 是一个经典的二元(y=0 或 y=1) 分类算法, 不是回归 输入特征还是线性回归, 输出是 [0,1] 的一个概率值, 其判别函数的形式为: \(P(y=1|x) = \frac {1}{1+ ...
- Android Studio总结
课程背景 相信大家对Android Studio已经不陌生了,Android Studio是Google于2013 I/O大会针对Android开发推出的新的开发工具,目前很多开源项目都已经在采用,G ...
- 关于python中lambda 函数使用小结
例子: 如果定义普通函数,一般都是这样写: def:ds(x): return 2*x+1 调用即: ds(5) 如果用lambda函数就是这么写,就是一句话: g =lambda x:2*x+1 调 ...
- 云服务器ECS(Elastic Compute Service),知识点
资料 网址 什么是云服务器ECS https://help.aliyun.com/document_detail/25367.html?spm=a2c4g.11186623.6.544.4e1e376 ...
- sudo:有效用户 ID 不是 0,sudo 属于 root 并设置了 setuid 位吗?
由于误操作导致无法使用sudo切换root用户 直接进入root用户并恢复文件权限,解决办法: chmod 4755 /usr/bin/sudo chmod 755 /usr/libexec/ses ...
- 修改MyEclipse/Eclipse左侧文字大小(MacOS/Windows)
一.Windows 首先找到 Eclipse/MyEclipse 的安装目录,然后找到如下目录: \plugins\org.eclipse.ui.themes_1.1.200.v20160815-05 ...
- Pandas | 14 统计函数
统计方法有助于理解和分析数据的行为.可以将这些统计函数应用到Pandas的对象上. pct_change()函数 系列,DatFrames和Panel都有pct_change()函数.此函数将每个元素 ...
- ESA2GJK1DH1K基础篇: 移植官方MQTT包,让TCP实现MQTT功能(以GPRS模块为例)
前言 这节代码将在这一节的基础上实现 拷贝第一节测试里面的MQTT文件夹到当前工程 当前工程建个MQTT的文件夹,用于存放那个MQTT文件夹里面的内容 添加文件到里面 注意:::: 实际源码拷贝位置 ...
- Huffman树与Huffman编码
1.Huffman树 今天复习Huffman树.依稀记得自己被Huffman树虐的经历.还记得是7月份,我刚开始看数据结构与算法,根本看不懂Huffman树的操作.后来我终于悟出了Huffman树是怎 ...