Open laizimo opened 6 years ago
上篇我在文章中分析了如何去实现瀑布流的布局,以及怎么使用模版去实现数据的插入到html之中。这一篇,主要讲一下三部分的实现,1.数据mock、2.下拉加载、3.上拉刷新。本次demo的地址在此,喜欢的可以给一个Star
首先,我们来分析一下数据的mock部分。由于想要实现与具备后台一样的效果,我们必须使用node去实现一个mock的后台,将数据放在json中,然后使用fs模块读取里面的内容,然后根据url进行数据的检索。
一般来说,下拉加载的数据都是具备分页特性的。主要可分为data(数据段)、page(当前页码)、next(告知前端接下来是否还有数据内容)。
之后,我们通过express框架对整个后端的数据进行一下模拟。我的demo目录下,有已经构造好的json文件,一共是两份,一份是更新前的数据,一份是更新后的数据。具体实现的代码:
const Express = require('express'); const app = new Express(); const path = require('path'); const fs = require('fs'); //data part app.get('/:id', function(req, res){ const page = req.params.id; res.setHeader("Access-Control-Allow-Origin", "*"); // console.log(page); fs.readFile(path.resolve(__dirname, 'mock.json'), function(err, data){ if(err){ throw err; } const static = JSON.parse(data).data; const arr = Array.from(static); const len = arr.length; const next = page - 0 + 1 <= len ? true : false; for(let value of arr){ if(value.page == page){ res.json({data: value.data, next: next}); } } }); }); app.get('/update/:id', function(req, res){ const page = req.params.id; res.setHeader('Access-Control-Allow-Origin', '*'); fs.readFile(path.resolve(__dirname, 'update.json'), function(err, data){ if(err){ throw err; } const static = JSON.parse(data).data; const arr = Array.from(static); const next = page - 0 + 1 <= arr.length ? true : false; let result = []; for(let value of arr){ if(value.page <= page){ result = result.concat(value.data); } } res.json({data: result, next: next}); }); }); app.listen(3000);
这部分主要是读取json文件中的数据,然后将它一个固定的json格式返回给前端。源码地址。
之后,我么开始来实现h5的下拉加载部分。
如果是我自己写的话,我会将下拉加载分成三个步骤进行实现:
但是,这样子的实现方式往往不是最佳的方式。最佳的方式,是类似与iscroll和better-scroll插件的方式。原理:在最外层设置一个wrapper(包),将包的大小绝对定位和内容隐藏,然后给内部的内容添加transform的动画属性,使得它可以进行上下的滚动。这样的好处是,可以实现回弹的效果。
原理图:
better-scroll在iscroll上面做了一些修缮,尤其是在触摸滚动方面吧。所以可以使用better-scroll来实现下拉加载和上拉刷新。
第一步:固定外层包的大小,使用绝对定位的方式。然后在内容的上下都添加loading图。示例:
<div id="wrapper"> <div> <div class="pull-refresh" id="pull-refresh"> <div class="arrow" id="arrow"> <img src="https://raw.githubusercontent.com/AlloyTeam/AlloyTouch/master/refresh/pull_refresh/asset/arrow.png" alt="arrow"><br> </div> </div> <div id="toploading"> <img src="./images/200.gif" alt="loading"> </div> <ul class="wrapper"> </ul> <div class="bottom" id="bottom"> <span class="line"></span> <span class="tip">我是底线</span> <span class="line"></span> </div> <div class="loading" id="loading"> <img src="./images/200.gif" alt="loading"> </div> </div> </div>
之后就是一些样式的设置。
第二步:初始化scroll的对象,可以通过BScroll去进行构造。然后在每次载入内容的时候都需要去刷新一下scroll,保证它对内部内容的识别是正确的。否则,你可能只能滚动一部分。(由于是ajax载入数据的,所以在刷新的时候需要一定的延时,才能保证内容的正确)
//init scroll part _initScroll: function(){ const _self = this; const wrapper = document.getElementById('wrapper') const options = { probeType: 1, click: true, scrollbar: false, bounduceTime: 2000 }; _self.scroll = new BScroll(wrapper, options); }, //ajax part fetch: function(url){ return new Promise((resolve, reject) => { $.ajax({ url: url, type: 'GET', dataType: 'json', data: {}, success: function(data){ resolve(data); }, error: function(){ reject('request timeout'); } }); }); }, load: function(fn){ const _self = this; const url = _self.config.base_url + _self.data.page; _self.operations.bShow(); _self.scroll.refresh(); return _self.fetch(url).then(data => { setTimeout(() => { _self.operations.bHide(); _self.data.next = data.next; if(!data.next){ _self.bottomLine(); } _self.data.page++; fn.call(_self, data.data); _self.data.status = 'ready'; }, 500); setTimeout(() => { _self.scroll.refresh(); }, 600); }, err => { console.log(err); }).catch(e => console.log(e)); }, update: function(fn){ const _self = this; const url = _self.config.base_url + 'update/' + (_self.data.page - 1); _self.operations.tShow(); _self.operations.aHide(); return _self.fetch(url).then(data => { setTimeout(() => { _self.operations.tHide(); _self.operations.aShow(); _self.data.next = data.next; fn.call(_self, data.data); }, 500); setTimeout(() => { _self.scroll.refresh(); _self.data.status = 'ready'; }, 600); }, er => { console.log(err); }).catch(e => console.log(e)); },
这部分主要分为三个函数fetch、load、update。它们的作用分别是fetch主要是一个发起ajax请求的函数,以promise的形式,将内容返回回来,便于后面的数据操作。load主要作用就是获取下拉加载的数据,将它加载到html中去,update是上拉刷新后的数据,将它重新替换html中列表部分的内容。这里有一个status去控制加载的状态,防止重复发送ajax请求。
第三步:就是给scroll去添加事件。主要是两个事件touchEnd和scroll事件。这里的scroll事件是当滚动列表时发生整体的滚动时才会触发的。因为我们的html结构中,wrapper内的内容除了ul列表之外头部和尾部都还具备loading的标签。
bind: function(){ const _self = this; _self.scroll.on('touchEnd', function(position){ if(position.y < _self.scroll.maxScrollY - 20){ _self.more(); }else if(position.y > 80){ _self.update(_self.initHtml); } }); _self.scroll.on('scroll', function(position){ if(position.y > 80){ _self.operations.up(); }else{ _self.operations.down(); } }); },
然后通过后端传过来的next可以帮助我们去判断是否还有后续内容,position.y对应的就是transform动画滚动时的值。然后,去判断是否到达底部是,我们还需要的是scroll中maxScrollY这个值。其中的20只是一个阈值。
这样其实一个下拉刷新和上拉加载的过程就算是完成了。后续还可以改进的地方有是图片的懒加载和js模版引擎的使用。
前言
上篇我在文章中分析了如何去实现瀑布流的布局,以及怎么使用模版去实现数据的插入到html之中。这一篇,主要讲一下三部分的实现,1.数据mock、2.下拉加载、3.上拉刷新。本次demo的地址在此,喜欢的可以给一个Star
正文
首先,我们来分析一下数据的mock部分。由于想要实现与具备后台一样的效果,我们必须使用node去实现一个mock的后台,将数据放在json中,然后使用fs模块读取里面的内容,然后根据url进行数据的检索。
一般来说,下拉加载的数据都是具备分页特性的。主要可分为data(数据段)、page(当前页码)、next(告知前端接下来是否还有数据内容)。
之后,我们通过express框架对整个后端的数据进行一下模拟。我的demo目录下,有已经构造好的json文件,一共是两份,一份是更新前的数据,一份是更新后的数据。具体实现的代码:
这部分主要是读取json文件中的数据,然后将它一个固定的json格式返回给前端。源码地址。
之后,我么开始来实现h5的下拉加载部分。
如果是我自己写的话,我会将下拉加载分成三个步骤进行实现:
但是,这样子的实现方式往往不是最佳的方式。最佳的方式,是类似与iscroll和better-scroll插件的方式。原理:在最外层设置一个wrapper(包),将包的大小绝对定位和内容隐藏,然后给内部的内容添加transform的动画属性,使得它可以进行上下的滚动。这样的好处是,可以实现回弹的效果。
原理图:
better-scroll在iscroll上面做了一些修缮,尤其是在触摸滚动方面吧。所以可以使用better-scroll来实现下拉加载和上拉刷新。
第一步:固定外层包的大小,使用绝对定位的方式。然后在内容的上下都添加loading图。示例:
之后就是一些样式的设置。
第二步:初始化scroll的对象,可以通过BScroll去进行构造。然后在每次载入内容的时候都需要去刷新一下scroll,保证它对内部内容的识别是正确的。否则,你可能只能滚动一部分。(由于是ajax载入数据的,所以在刷新的时候需要一定的延时,才能保证内容的正确)
这部分主要分为三个函数fetch、load、update。它们的作用分别是fetch主要是一个发起ajax请求的函数,以promise的形式,将内容返回回来,便于后面的数据操作。load主要作用就是获取下拉加载的数据,将它加载到html中去,update是上拉刷新后的数据,将它重新替换html中列表部分的内容。这里有一个status去控制加载的状态,防止重复发送ajax请求。
第三步:就是给scroll去添加事件。主要是两个事件touchEnd和scroll事件。这里的scroll事件是当滚动列表时发生整体的滚动时才会触发的。因为我们的html结构中,wrapper内的内容除了ul列表之外头部和尾部都还具备loading的标签。
然后通过后端传过来的next可以帮助我们去判断是否还有后续内容,position.y对应的就是transform动画滚动时的值。然后,去判断是否到达底部是,我们还需要的是scroll中maxScrollY这个值。其中的20只是一个阈值。
总结
这样其实一个下拉刷新和上拉加载的过程就算是完成了。后续还可以改进的地方有是图片的懒加载和js模版引擎的使用。