之前项目中的列表是采用的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< www.tayuLept.cn /li>
<li>item4</www.aomenyonli.cn li>
<li>item5</www.zyzxylvip.cn 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( www.niucaiyule1.cn 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[ www.xinhuoyule88.com 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 = www.wmsjwz.cn false;
return;
}

第一个条件判断只要是定义了这次滑动的方向是什么。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. www.yongshiyule178.com 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的那些事——内容不足时下拉刷新的更多相关文章

  1. IScroll那些事——内容不足时下拉刷新

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

  2. iscroll 下拉刷新,上拉加载

    新手,直接贴代码了 <!DOCTYPE html><html class=""><head lang="en"><me ...

  3. ListView(2)最简单的上拉刷新,下拉刷新

    最简单的上拉刷新和下拉刷新,当listview滚动到底部时向上拉刷新数据.当listview滚动到最顶部时下拉刷新.       图1,上拉刷新 图2,下拉刷新 1,设置lisview,加载heade ...

  4. ListView(2)最简单的上拉刷新、下拉刷新代码

    效果 最简单的上拉刷新和下拉刷新,当listview滚动到底部时向上拉刷新数据.当listview滚动到最顶部时下拉刷新.       图1,上拉刷新 图2,下拉刷新 1.设置lisview 加载he ...

  5. iscroll.js 下拉刷新和上拉加载

    html代码如下 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> < ...

  6. iScroll 下拉刷新

    <!doctype html> <html> <head> <meta charset="utf-8"> <script ty ...

  7. iscroll.js实现上拉刷新,下拉加载更多,应用技巧项目实战

    上拉刷新,下拉加载更多...仿原生的效果----iscroll是一款做滚动效果的插件,具体介绍我就不废话,看官方文档,我只写下我项目开发的一些用到的用法: (如果不好使,调试你的css,想必是个很蛋疼 ...

  8. 基于iscroll实现下拉和上拉刷新

    在原生APP的开发中,有一个常见的功能,就是下拉刷新的功能,这个想必大家都是知道的,但是原生APP的开发,有一个很大的问题就是,你每次更新一些功能,就要用户重新下载一次版本,尤其是在iOS系统中,新版 ...

  9. H5基于iScroll实现下拉刷新,上拉加载更多

    前言 前一段有个手机端的项目需要用到下拉刷新和上拉加载更多的效果,脑海里第一反映就是微博那种效果,刚开始的理解有些偏差,以为下拉也是追加数据,上拉也是追加数据,后请教同事后发现其实下拉只是刷新最新数据 ...

随机推荐

  1. Maven学习笔记-03-Eclipse和Maven集成

    本文使用 Eclipse 集成 Maven,并创一个基于 maven的web工程 一 环境版本信息 本文使用的版本信息如下: Eclipse Version: Mars.1 Release (4.5. ...

  2. C# WPF DataGrid 分组(Group)

    原文:C# WPF DataGrid 分组(Group) 效果如图,每个列的名字可以自定义.我随便用了”File”和”Attachment Name”.  在Window的Resources里面设置S ...

  3. 绍一集训Round#2

    Preface 感觉这次的题目是真的太水了,可能是为了让我们涨一波信心的吧. 不过最后一题没有想到那种玄学做法还是太菜了,还是要一波姿势的啊. 交换 一道入门难度题,根据排序不等式(又或是简单推导可以 ...

  4. Python高阶函数--map

    map()函数 map()是 Python 内置的高阶函数,它接收一个函数 f 和一个 list,并通过把list 的每个元素依次作用在函数 f 上,得到一个新的 list 并返回. 例如,对于lis ...

  5. Vue 实际项目中你可能会遇见问题

    纸上得来终觉浅,绝知此事要躬行! Vue的文档和教程看的太多,小的demo做的多,也不如自己实际的进行一个完整项目的开发.只有做了才知道原来问题这么多,这里列举了一些你做demo教程可能不会遇见的坑. ...

  6. Mvc4_ @RenderBody、@RenderPage、@RenderSection用法

    一.@RenderBody 当创建基于_Layout.cshtml布局页面的视图时,视图的内容会和布局页面合并,而新创建视图的内容会通过_Layout.cshtml布局页面的@RenderBody() ...

  7. 基本的排序算法C++实现(插入排序,选择排序,冒泡排序,归并排序,快速排序,最大堆排序,希尔排序)

    博主欢迎转载,但请给出本文链接,我尊重你,你尊重我,谢谢~http://www.cnblogs.com/chenxiwenruo/p/8529525.html特别不喜欢那些随便转载别人的原创文章又不给 ...

  8. 百度之星-day2-1004-二分答案

    由于序列有序,求其中一个最优解,二分答案即可,注意二分时上边界满足才保存 #include<iostream> #include<stdio.h> #include<st ...

  9. 跟踪分析Linux内核的启动过程--实验报告 分析 及知识重点

    跟踪分析Linux内核的启动过程 攥写人:杨光  学号:20135233 ( *原创作品转载请注明出处*) ( 学习课程:<Linux内核分析>MOOC课程http://mooc.stud ...

  10. MySQL: Connection Refused,调整 mysql.ini中的 max_connections

    连接相同的结构的MySQL数据库,一套库Tomcat启动正常,另一套库一直报Connection Refused. 可以断定是连接数太小了.查找mysql.ini中的 max_connections, ...