写在前面

列表一直是展示数据的一个重要方式,在手机端的列表展示又和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. ASP.NET没有魔法——ASP.NET MVC 与数据库之MySQL

    之前介绍了My Blog如何使用ADO.NET来访问SQL Server获取数据.本章将介绍如何使用My SQL来完成数据管理. 在使用My SQL之前需确保开发环境中安装了My SQL数据库和Con ...

  2. struts2中的结果视图类型

    实际上在Struts2框架中,一个完整的结果视图配置文件应该是: <action name="Action名称" class="Action类路径" me ...

  3. style里的文字 背景 样式以及边框

    <style>        body{background:#FCC;}        .c00 div{ margin:0 auto; padding:0;}        #a01{ ...

  4. python抓取zabbix图形,并发送邮件

    最近十九大非常烦,作为政府网站维护人员,简直是夜不能寐.各种局子看着你,内保局,公安部,360,天融信,华胜天成,中央工委,政治委员会... 360人员很傻X,作为安全公司,竟然不能抓到XX网站流量, ...

  5. C#委托

    关于什么是委托,委托如何使用,我在这里就不说了. 需要说的: 委托是函数指针链 委托的 BeginInvoke 委托如果出现异常,会如何 如果不知道函数指针,可以继续往下看,我来告诉大家,为何需要委托 ...

  6. 解决网络通信中外网和内网之间的通信问题(NAT转换)

    本文原址 http://www.cnblogs.com/lidabo/p/3828846.html 在网络编码中会发现程序在局域网中是可以适用的,但是在外网与内网之间和内网与内网之间就不可行.问题就在 ...

  7. UVa12100,Printer Queue

    水题,1A过的 数据才100,o(n^3)都能过,感觉用优先队列来做挺麻烦的,直接暴力就可以了,模拟的队列,没用stl #include <iostream> #include <c ...

  8. Kotlin——最详细的数据类型介绍

    任意一种开发语言都有其数据类型,并且数据类型对于一门开发语言来说是最基本的构成,同时也是最基础的语法.当然,kotlin也不例外.kotlin的数据类型和Java是大致相同的,但是他们的写法不同,并且 ...

  9. 容器与Docker简介(四)Docker容器,镜像与 Registries——微软微服务电子书翻译系列

    当使用Docker时,开发人员创建一个应用程序或服务,并将其和其依赖关系打包到容器镜像中. 镜像是应用程序或服务及其配置和依赖的静态表示形式. 要运行应用程序或服务,应用程序的镜像将被实例化以创建一个 ...

  10. 本地文件与服务器文件同步shell脚本。

    #!/bin/sh read -t 30 -p "请输入项目名:" name echo -e "\n" echo "项目名为:$name" ...