写在前面

列表一直是展示数据的一个重要方式,在手机端的列表展示又和PC端展示不同,毕竟手机端主要靠滑。之前手机端之前一直使用的IScroll,但是IScroll本身其实有很多兼容性BUG,想改动一下需求也很不容易,可以看我之前写的这一文章IScroll那些事——内容不足时下拉刷新(这里并不是说IScroll不好,里面对手机、浏览器兼容性都做了大量的处理,只是当遇到bug时或者想改一下需求时不时特别方便,毕竟是一个这么大的库)。因此也一直想了解一下这类列表的实现原理,万一真到时候可以自己写一个,这样自己维护自己的代码也可以更加得心应手。

下面主要是阅读了饿了么UI组件库mint-ui然后编写出来的效果图:

代码请看这里:github

移动端效果之swiper

移动端效果之picker

移动端效果之cellSwiper

移动端效果之IndexList

1 核心解析

1.1 整体思路图

1.2 HTML结构

<div class="page-loadmore-wrapper">
<div id='loadMore' class="loadmore">
<div id="loadMoreContent" class="loadmore-content">
<!-- 这里是顶部状态生成的地方 -->
<ul class="page-loadmore-list" id="loadMoreList"></ul>
<!-- 这里是底部状态生成的地方 -->
</div>
</div>
</div>

这里有一点需要注意,滑动内容部分需要一个设置为overflow:scroll的容器,如果不设置,就会一直向上找,直到最后返回window,这点在下面的代码可以体现

/**
* 获取滚动容器
* @param DOM element
* @return
*/
getScrollEventTarget: function(element) {
var currentNode = element;
while (currentNode && currentNode.tagName !== 'HTML' &&
currentNode.tagName !== 'BODY' && currentNode.nodeType === 1) {
var overflowY = document.defaultView.getComputedStyle(currentNode).overflowY;
if (overflowY === 'scroll' || overflowY === 'auto') {
return currentNode;
}
currentNode = currentNode.parentNode;
}
return window;
}

1.3 滑动弹性与状态变化

这两点我们在touchmove事件中可以找到相应的代码:

// 弹性滑动
// 这里用手指滑动的位移除以比例系数来得出内容应该滑动的位移
// 因此这里的内容滑动的位移一定是会小于手指滑动的位移的,除非你将系列设置为小于1,那我就没得话说了
// 于是就造成了一种滑动又滑不动的感觉
var distance = (_this.currentY - _this.startY) / _this.config.distanceIndex; // 下移条件
// 1. 必须有刷新函数
// 2. 方向为向下
// 3. 初始的scrollTop为0
// 4. 状态不为加载中
if (typeof _this.config.topMethod === 'function' && _this.direction === 'down' &&
_this.getScrollTop(_this.scrollEventTarget) === 0 && _this.topStatus !== 'loading') {
event.preventDefault();
event.stopPropagation(); if (_this.config.maxDistance > 0) {
_this.translate = distance <= _this.config.maxDistance ? distance - _this.startScrollTop : _this.translate;
} else {
_this.translate = distance - _this.startScrollTop;
} if (_this.translate < 0) {
_this.translate = 0;
} // 这里是滑动中(touchmove)时应该判断的
// 如果滑动的位移操作了我们设置的值就置为pull
// 同时更新状态,改变内容的transform
// 同理可以在向上拉动的时候找到相应的代码,这里不作累述
_this.topStatus = _this.translate >= _this.config.topDistance ? 'drop' : 'pull'; Event.trigger('topStatus', _this.topStatus);
Event.trigger('translate', _this.translate);
} // 在向上滑动的过程中,还需要时刻检测是否已经滑倒最下面了
// 如果没有滑倒最下面,则正常滑动,否则,加载新的数据
if (_this.direction === 'up') {
_this.bottomReached = _this.bottomReached || _this.checkBottomReached();
}

1.4 加载数据

当状态在loading的时候,就是加载数据的时候,而只有当滑动停止之后,状态才需要置为loading,因此加载数据的代码需要在touchend中执行,具体看下面代码注释:

// 这里分析向下刷新数据时候的代码
// 向上部分的类似,可以自行去了解
if (_this.direction === 'down' && _this.getScrollTop(_this.scrollEventTarget) === 0 && _this.translate > 0) {
// 这里触发topDropped为true是为了给内容部分加上动画
Event.trigger('topDropped', true); // 判断当前是否已经拉倒了足够的位移,只有状态为drop的时候放手才会加载数据
if (_this.topStatus === 'drop') {
// 重置状态为loading,改变位移
Event.trigger('topStatus', 'loading');
// 向下移动50px像素是为了展示出loading的文字
Event.trigger('translate', 50); // 加载数据
_this.config.topMethod(function() {
var args = [].slice.call(arguments);
_this.onTopLoaded.apply(_this, args);
});
} else {
// 如果向下拉动状态仍为pull,说明拉动的距离很小
Event.trigger('translate', 0);
Event.trigger('topStatus', 'pull');
}
}

1.5 上拉加载数据完成之后

这里与下拉刷新有一点小小的不同,这里贴一下代码:

onBottomLoaded: function(list, isAllLoaded) {
Event.trigger('bottomStatus', 'pull');
Event.trigger('bottomDropped', false);
Event.trigger('data', list); // 这里给scrollEventTarget设置了scrollTop为50是为了防止跳动
if (this.scrollEventTarget === window) {
document.body.scrollTop += 50;
} else {
this.scrollEventTarget.scrollTop += 50;
} Event.trigger('translate', 0);
this.bottomAllLoaded = isAllLoaded;
}

1.6 关于数据初始化填充

在数据内容不足一屏时,如果设置了autoFill字段为true的话,会自动调用一遍bottomMethod来填充数据

fillContainer: function() {
var _this = this; // 如果自动填充
if (this.config.autoFill) {
// 根据滚动容器来判断当前数据是否已经填充满容器
if (this.scrollEventTarget === window) {
this.containerFilled = this.$el.getBoundingClientRect().bottom >=
document.documentElement.getBoundingClientRect().bottom;
} else {
this.containerFilled = this.$el.getBoundingClientRect().bottom >=
this.scrollEventTarget.getBoundingClientRect().bottom;
} // 如果数据没有填充满容器,则加载数据
if (!this.containerFilled) {
// 这里算是一点小遗憾,为了在自动加载loading的时候,显示出状态
// 将内容部分位移了-50px,这就是为什么在自动加载的时候会出现一个跳动的过程
Event.trigger('bottomStatus', 'loading');
Event.trigger('translate', -50);
var data = this.config.bottomMethod(function(list) {
Event.trigger('data', list);
Event.trigger('bottomStatus', 'pull');
Event.trigger('translate', 0);
});
}
}
},

2 总结

最开始会认为这样的效果实现起来会比较复杂(不过实际上确实也写了快500到600行代码了

移动端效果之LoadMore的更多相关文章

  1. 移动端效果之ScrollList

    写在前面 列表一直是展示数据的一个重要方式,在手机端的列表展示又和PC端展示不同,毕竟手机端主要靠滑.之前手机端之前一直使用的IScroll,但是IScroll本身其实有很多兼容性BUG,想改动一下需 ...

  2. 移动端效果之Swiper

    写在前面 最近在做移动端方面运用到了饿了么的vue前端组件库,因为不想单纯用组件而使用它,故想深入了解一下实现原理.后续将会继续研究一下其他的组件实现原理,有兴趣的可以关注下. 代码在这里:戳我 1. ...

  3. 移动端效果之Picker

    写在前面 接着前面的移动端效果的研究,这次来看看picker选择器的实现原理 移动端效果之Swiper 代码看这里:github 1. 核心解析 1.1 基本HTML结构 <!-- 说明: 1. ...

  4. 移动端效果之CellSwiper

    写在前面 接着之前的移动端效果讲解,刚好项目中需要使用到这一效果,去饿了么的组件库看了一下效果,发现效果和微信端的cellSwiper还是有点差别的,由于项目中又是使用的React,之前使用的Reac ...

  5. 移动端效果之IndexList

    写在前面 接着前面的移动端效果讲,这次讲解的的是IndexList的实现原理.效果如下: 代码请看这里:github 移动端效果之swiper 移动端效果之picker 移动端效果之cellSwipe ...

  6. 移动端使用mint-ui loadmore实现下拉刷新上拉显示更多

    前序:在使用vue做一个h5项目的时候,需要上拉分页加载,实践中总结一下: 首先要安装mint-ui npm i mint-ui -S 然后引入,一般在main.js里面 import Vue fro ...

  7. flow-vue.js移动端效果

    得益于vue.js和element,以及vue-element-extends在线表格编辑.前后端分离的后端用golang+beego框架,服务器采用腾讯云. vue的自适应做的很好,只要将侧栏加一行 ...

  8. 动端逐渐出了许多的移动端的框架,比如Sencha Touch、JQTouch、Jquery-moblie、jqMobi等等。这些框架都有优缺点,不同的框架应用在不同的项目中。现简单阐述一下各框架的优缺点:

    移动前端工作的那些事---前端制作之微信小技巧篇   (2013-11-15 15:20) 转载▼ 标签: it css3/javascript html5 webapp 手机网站搭建 分类: 前端制 ...

  9. 使用three.js实现机器人手臂的运动效果

    Three.js 是一款运行在浏览器中的 3D 引擎,你可以用它创建各种三维场景,包括了摄影机.光影.材质等各种对象.你可以在它的主页上看到许多精彩的演示.不过,这款引擎目前还处在比较不成熟的开发阶段 ...

随机推荐

  1. Maven打包Jar

    现状 该项目使用了Maven,并且引入了Spring,包含代码.配置文件.Jar包,使用的是IDEA来作为开发工具,项目的产出物是要打包成一个可运行的Jar包.通过IDEA的打包工具也可以打包成功,只 ...

  2. Java面向对象 IO (一)

     Java面向对象  IO  (一) 知识概要:                (1)IO概述 (2)IO流的常用基类 (3)IO程序的书写 (4)字符流  写入  读取  文本文件的两种读取方式 ...

  3. DevOps之域名

    唠叨话 关于德语噢屁事的知识点,仅提供精华汇总,具体知识点细节,参考教程网址,如需帮助,请留言. 域名系统DNS(Domain Name System) 关于域名,知识与技能的层次(知道.理解.运用) ...

  4. This application failed to start because it could not find or load the Qt platform plugin "windows" 的问题原因以及解决方案

    1. 问题原因非常简单,经过各种百度,都没有找到解决方案,在此做一个记录备用. 2.原因就在于,项目目录使用了中文路径,然后出现了这个问题. 3.我是在使用 syncfusion 下的HTML 转PD ...

  5. 当 ReactJS 遇到 TypeScript

    由于本人应用项目主要是2B的web应用程序, 所以以下暂不谈react的服务端渲染和react navie, 先说说ReactJS: React 的组件化和  数据单向绑定 的模式(flux) 使应用 ...

  6. java基础---java语言概述

    一.计算机编程的两种范型 1.面向过程的模型---具有线性执行特点,认为是代码作用于数据. 2.面向对象的模型---围绕它的数据(即对象)和为这个数据定义的接口来组织程序:实际上是用数据控制代码的访问 ...

  7. 声明数组变量/// 计算所有元素的总和/打印所有元素总和/输出/foreach循环/数组作为函数的参数/调用printArray方法打印

    实例 下面是这两种语法的代码示例: double[] myList; // 首选的方法 或 double myList[]; // 效果相同,但不是首选方法 创建数组 Java语言使用new操作符来创 ...

  8. win10 uwp Window.Current.Dispatcher中Current为null

    本文说的是进行网络中异步界面出现的错误,可能带有一定的主观性和局限性,说的东西可能不对或者不符合每个人的预期.如果觉得我有讲的不对的,就多多包含,或者直接关掉这篇文章,但是请勿生气或者发怒吐槽,可以在 ...

  9. (转)UML类图与类的关系详解

    转载自:http://www.uml.org.cn/oobject/201104212.asp 在画类图的时候,理清类和类之间的关系是重点.类的关系有泛化(Generalization).实现(Rea ...

  10. C++类与对象(05)

    类是具有惟一标识符的实体:在类中声明的任何成员不能使用extern.auto和register关键字进行修饰:类中声明的变量属于该类,在某些情况下,变量也可以被该类的不同实例所共享. 访问权限用于控制 ...