IScroll那些事_当内容不足时下拉刷新的解决方法


Posted in Javascript onJuly 18, 2017

之前项目中的列表是采用的IScroll,但是在使用IScroll有一个问题就是:当内容不足全屏的时候,是木有办法往下拉的,这样就达不到刷新的目的了。【这是本人工作中遇到的,具体例子具体分析,这里只作一个参考】

大致的例子是这样的:

<style>
 * {
 margin: 0;
 padding: 0;
 }
 html,body,.container {
 width: 100%;
 height: 100%;
 }
 .container>ul>li {
 padding: 15px 20px;
 text-align: center;
 border-bottom: 1px solid #ccc;
 }
</style>

<div id="container" class="container">
 <ul class="scroller">
 <li>item1</li>
 <li>item2</li>
 <li>item3</li>
 <li>item4</li>
 <li>item5</li>
 </ul>
</div>

<script src="https://cdn.bootcss.com/iScroll/5.2.0/iscroll.min.js"></script>
<script>
 var myScroll = null;
 function onLoad() {
 myScroll = new IScroll('container');
 }
 window.addEventListener('DOMContentLoaded', onLoad, false);
</script>

那么,既然超过一屏是可以刷新的,那我们就来逛逛代码吧。在github上搜索iscroll,打开第一个,找到src下面的core.js。

1. 思路

首先既然要下拉,肯定会触发touchstart、touchmove以及touchend事件。搜索touchmove,很好,在_initEvents中的注册了这个事件。

_initEvents: function (remove) {
 // ...
 // 这里省略若干代码

 if ( utils.hasTouch && !this.options.disableTouch ) {
  eventType(this.wrapper, 'touchstart', this);
  eventType(target, 'touchmove', this);
  eventType(target, 'touchcancel', this);
  eventType(target, 'touchend', this);
 }

 // ...
},

好吧,看到这里的时候,我表示懵了一下逼,这不就是个绑定事件么?this又是一个什么鬼,然后我去查了一下文档,发现了这么一个东西。文档地址

target.addEventListener(type, listener[, options]);
target.addEventListener(type, listener[, useCapture]);
target.addEventListener(type, listener[, useCapture, wantsUntrusted ]); 
// 
// Gecko/Mozilla only

listener

当所监听的事件类型触发时,会接收到一个事件通知(实现了 Event 接口的对象)对象。listener 必须是一个实现了 EventListener 接口的对象,或者是一个函数

木有看错,listener是一个对象或者是一个函数。前提是这个对象实现了EventListener接口。我们接着往下看,发现了这么一个例子。

var Something = function(element) {
 // |this| is a newly created object
 this.name = 'Something Good';
 this.handleEvent = function(event) {
 console.log(this.name); 
 // 'Something Good', as this is bound to newly created object
 switch(event.type) {
  case 'click':
  // some code here...
  break;
  case 'dblclick':
  // some code here...
  break;
 }
 };

 // Note that the listeners in this case are |this|, not this.handleEvent
 element.addEventListener('click', this, false);
 element.addEventListener('dblclick', this, false);

 // You can properly remove the listeners
 element.removeEventListener('click', this, false);
 element.removeEventListener('dblclick', this, false);
}
var s = new Something(document.body);

然后在去IScroll的源码去找,发现了同样的实现方式。在default文件夹中有一个handleEvent.js。

好了,这个梗先告一段落。还是继续看源码。在handleEvent.js中,有这么一段东西。

handleEvent: function (e) {
 switch ( e.type ) {
  case 'touchstart':
  case 'pointerdown':
  case 'MSPointerDown':
  case 'mousedown':
  this._start(e);
  break;
  case 'touchmove':
  case 'pointermove':
  case 'MSPointerMove':
  case 'mousemove':
  this._move(e);
  break;
  case 'touchend':
  case 'pointerup':
  case 'MSPointerUp':
  case 'mouseup':
  case 'touchcancel':
  case 'pointercancel':
  case 'MSPointerCancel':
  case 'mousecancel':
  this._end(e);
  break;
  // ...
 }
 }
};

发现在start/move/end分别调用了内部方法_start/_move/_end方法。去看看这三个方法,看其中可能会引起不会滑动的点。

在_start方法中,看到这样的几行代码,会不会是直接返回了呢?分析分析:

if ( !this.enabled || (this.initiated && utils.eventType[e.type] !== this.initiated) {
 return;
}

// ...

var point = e.touches ? e.touches[0] : e,
 pos;

this.initiated = utils.eventType[e.type];
this.moved = false;
initiated属性在最开始肯定是没有的,而enabled默认是true,所以在最开始执行这个方法的时候是不会返回的,而是会给initiated这个属性设置当前的eventType值,这个值会在_move方法中用到。重点来看看_move方法。

if ( !this.enabled || utils.eventType[e.type] !== this.initiated ) {
 return;
}

首先来进行类型判断,因为在_start方法中已经定义了这个值,所以这里也不会返回。接着往下看:

if ( timestamp - this.endTime > 300 && (absDistX < 10 && absDistY < 10) ) {
 return;
}

【实际上是两次click事件的模拟】如果两次滑动的时间大于了300ms,并且只要一个方向上的位移少于10像素,那么也是会返回的。那么会不会呢,打个断点测试一下就知道了。这里就不贴图了,实际中的测试结果是,每一次移动肯定是在300ms以内的,这里之所以判断300ms,主要是click事件执行会有一个300ms的延迟。而每一次移动,由于手指的触点比较大,还是会大于10像素的,即使两次不大于10像素,也是不影响的。所以这点不会返回。那么继续接着看:

// If you are scrolling in one direction lock the other
if ( !this.directionLocked && !this.options.freeScroll ) {
 if ( absDistX > absDistY + this.options.directionLockThreshold ) {
 this.directionLocked = 'h'; // lock horizontally
 } else if ( absDistY >= absDistX + this.options.directionLockThreshold ) {
 this.directionLocked = 'v'; // lock vertically
 } else {
 this.directionLocked = 'n'; // no lock
 }
}

if ( this.directionLocked == 'h' ) {
 if ( this.options.eventPassthrough == 'vertical' ) {
 e.preventDefault();
 } else if ( this.options.eventPassthrough == 'horizontal' ) {
 this.initiated = false;
 return;
 }

 deltaY = 0;
} else if ( this.directionLocked == 'v' ) {
 if ( this.options.eventPassthrough == 'horizontal' ) {
 e.preventDefault();
 } else if ( this.options.eventPassthrough == 'vertical' ) {
 this.initiated = false;
 return;
 }

 deltaX = 0;
}

第一个条件判断只要是定义了这次滑动的方向是什么。h表示水平方向,v表示竖直方向。我们是要向下滑动,所以我们关注的是竖直方向。看第二个条件判断,如果是竖直方向,那么将水平方向的deltaX值变为0。这样做的目的是保持绝对的竖直方向。因为移动实际还是根据元素的位移值来的。当probe的版本为2以下的时候,是根据css3的transform属性来移动位移的,为3版本的时候是根据决定对位来移动的。所以这里只要不把我们的deltaY置为0就说明木有什么问题。继续往下看代码:

deltaX = this.hasHorizontalScroll ? deltaX : 0;
deltaY = this.hasVerticalScroll ? deltaY : 0;

newX = this.x + deltaX;
newY = this.y + deltaY;
// ...

// 这里是移动
this._translate(newX, newY);

测试中发现,这个hasVerticalScroll一直是false,那么deltaY一直就是0,也就是移动了也白移动。找到问题原因。那么,这个hasVerticalScroll是从哪里来的?全局找呀找,在refresh中找到这样几行代码:

this.wrapperWidth = this.wrapper.clientWidth;
this.wrapperHeight = this.wrapper.clientHeight;

var rect = utils.getRect(this.scroller);
/* REPLACE START: refresh */

this.scrollerWidth = rect.width;
this.scrollerHeight = rect.height;

this.maxScrollX = this.wrapperWidth - this.scrollerWidth;
this.maxScrollY = this.wrapperHeight - this.scrollerHeight;

/* REPLACE END: refresh */

this.hasHorizontalScroll = this.options.scrollX && this.maxScrollX < 0;
this.hasVerticalScroll = this.options.scrollY && this.maxScrollY < 0;

refresh方法会在IScroll实例化的时候调用一次。粗略一看,scrollY内置为true,所以只有maxScrollY会大于0。往上看。this.wrapperHeight - this.scrollerHeight肯定是大于0的呀,这就是问题所在。

那么看看我们最开始代码,这里的wrapperHeight为文档高度,scrollerHeight为内容高度,所以wrapperHeight高度始终大于scrollHeight。但是,手机端页面夹杂的列表,一般都有头部、底部,而中间部分一般都会采用padding的形式来使得列表在全局滚动,这样就不需要每次都要特定地计算列表的高度。

2. 解决方案

针对以上问题,只要我们能够使内部的滚动部分高度大于容器高度,那么就能触发滚动。

2.1 粗略做法

可以设置一个min-height属性为900px(900只是一个示例,只要够大就可以),这样就可以保证可以滑动。

2.2 精准做法

计算当前的容器高度,然后比容器高度多一个像素即可。

以上这篇IScroll那些事_当内容不足时下拉刷新的解决方法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
使用window.prompt()实现弹出用户输入的对话框
Apr 13 Javascript
jQuery实现提示密码强度的代码
Jul 15 Javascript
JavaScript组件开发完整示例
Dec 15 Javascript
javascript html5移动端轻松实现文件上传
Mar 27 Javascript
javascript输出AscII码扩展集中的字符方法
Dec 26 Javascript
js将键值对字符串转为json字符串的方法
Mar 30 Javascript
详解vue2.0监听属性的使用心得及搭配计算属性的使用
Jul 18 Javascript
VueJS 组件参数名命名与组件属性转化问题
Dec 03 Javascript
基于Vue的商品主图放大镜方案详解
Sep 19 Javascript
微信小程序订阅消息(java后端实现)开发
Jun 01 Javascript
Vue Render函数创建DOM节点代码实例
Jul 08 Javascript
JS如何监听div的resize事件详解
Dec 03 Javascript
angular使用bootstrap方法手动启动的实例代码
Jul 18 #Javascript
详解jQuery中关于Ajax的几个常用的函数
Jul 17 #jQuery
js实现首屏延迟加载实现方法 js实现多屏单张图片延迟加载效果
Jul 17 #Javascript
node.js中grunt和gulp的区别详解
Jul 17 #Javascript
js实现多张图片延迟加载效果
Jul 17 #Javascript
js指定步长实现单方向匀速运动
Jul 17 #Javascript
webpack构建vue项目的详细教程(配置篇)
Jul 17 #Javascript
You might like
mysql4.1以上版本连接时出现Client does not support authentication protocol问题解决办法
2007/03/15 PHP
php中防止恶意刷新页面的代码小结
2012/10/31 PHP
php对二维数组按指定键值key排序示例代码
2013/11/26 PHP
php 获取页面中指定内容的实现类
2014/01/23 PHP
PHP实现简单实用的分页类代码
2016/04/08 PHP
php正则判断是否为合法身份证号的方法
2017/03/16 PHP
tp5(thinkPHP5框架)captcha验证码配置及验证操作示例
2019/05/28 PHP
Yii框架实现对数据库的CURD操作示例
2019/09/03 PHP
php提高脚本性能的4个技巧
2020/08/18 PHP
JavaScript 学习笔记(五)
2009/12/31 Javascript
javascript preload&amp;lazy load
2010/05/13 Javascript
使用javascript实现Iframe自适应高度
2014/12/24 Javascript
jQuery EasyUI实现右键菜单变灰不可用效果
2015/09/24 Javascript
精彩的Bootstrap案例分享 重点在注释!(选项卡、栅格布局)
2016/07/01 Javascript
Angular2入门教程之模块和组件详解
2017/05/28 Javascript
Vue+Vux项目实践完整代码
2017/11/30 Javascript
浅谈Vue网络请求之interceptors实际应用
2018/02/28 Javascript
JS实现的透明度渐变动画效果示例
2018/04/28 Javascript
微信小程序提取公用函数到util.js及使用方法示例
2019/01/10 Javascript
React-redux实现小案例(todolist)的过程
2019/09/29 Javascript
微信小程序实现时间戳格式转换
2020/07/20 Javascript
Python 自动补全(vim)
2014/11/30 Python
编写Python爬虫抓取豆瓣电影TOP100及用户头像的方法
2016/01/20 Python
python 自动化将markdown文件转成html文件的方法
2016/09/23 Python
Python numpy 常用函数总结
2017/12/07 Python
对Python中gensim库word2vec的使用详解
2018/05/08 Python
用于业余项目的8个优秀Python库
2018/09/21 Python
python实现爬山算法的思路详解
2019/04/09 Python
Python爬虫抓取技术的一些经验
2019/07/12 Python
Python jieba库用法及实例解析
2019/11/04 Python
浅析Python面向对象编程
2020/07/10 Python
彪马荷兰官网:PUMA荷兰
2019/05/08 全球购物
应届生求职信写作技巧
2013/10/24 职场文书
低碳环保演讲稿
2014/08/28 职场文书
企业安全隐患排查治理制度
2015/08/05 职场文书
Java并发编程必备之Future机制
2021/06/30 Java/Android