赞
踩
基于小程序开发的列表加载更多例子。
基于小程序开发的列表加载更多例子。
运行效果(演示的小视频,点击播放即可)
总体思路如何:
1、通过scroll-view组件提供的bindscroll方法监控滚动的时候是否距离底部在40px内,如果小于40px则触发加载更多方法(见完整代码index.js里的bindscroll方法)
2、通过使用发现很多时候服务返回数据太快了,没有加载等待的过程,显的不自然,所以在loadMore方法里通过setTimeout来保证至少有333毫秒的加载时间(见完整代码index.js里的loadMore方法)
3、实际使用中又发现一个问题,上滑到底部会重复触发加载更多方法导致重复的网络请求。通过记录上次加载时间lastRequestTime,保证两次网络请求的间隔大于1秒(见完整代码index.js里的fetchList方法),这样就能避免重复调用加载更多的问题
备注:demo代码里的网络请求wx.requestTest方法是为了显示效果,所以写了个模拟的请求方法,实际使用可替换为wx.request对接自己项目的服务
具体实现如下:
1、创建小程序,点击下图里框起来的位置,创建小程序
2、在app.js里添加网络模拟方法
- let serverData = [];
- for(let i = 1; i < 25; i++){
- serverData.push({id:i, name:i})
- }
- App({
- onLaunch: function () {
- wx.requestTest = ({data:{page,size},success}) => {
- setTimeout(
- () => {
- //模拟网络返回请求
- let res = {
- data:{
- data:{
- rows: serverData.slice((page - 1) * size, size + (page - 1) * size)
- },
- result: true,
- }
- }
- console.log(res)
- success(res)
- },1000//模拟网络延迟
- )
- }
- },
- globalData: {
- }
- })
3、增加和pages同层级的components文件夹,在里面创建Loading文件夹,并在下面创建以下文件
- //loading.js
- Component({
- data: {
- },
- properties: {
- visible: {//loading效果是否显示
- type: Boolean,
- value: false//默认不显示
- },
- },
- })
- //loading.json
- {
- "component": true,//表示是组件
- "usingComponents": {}
- }
- //loading.wxss
- .loadmore {
- width: 100%;
- height: 0rpx;
- display: flex;
- align-items: center;
- justify-content: center;
- padding-top:24rpx;
- transition: all 200ms linear;
- }
- .loadmore.visible {
- height: 80rpx;
- }
- .my-loading:after {
- content: " ";
- display: block;
- width: 26px;
- height: 26px;
- margin: 1px;
- border-radius: 50%;
- border: 2px solid #FFD800;
- border-color: #fff transparent #FFD800 transparent;
- animation: lds-dual-ring 1.2s linear infinite;
- }
- @keyframes lds-dual-ring {
- 0% {
- transform: rotate(0deg);
- }
- 100% {
- transform: rotate(360deg);
- }
- }
- //loading.wxml
- <view class="loadmore {{visible && 'visible'}}">
- <view class="my-loading" wx:if="{{visible}}"></view>
- </view>
4、修改pages/index文件夹下各文件如下
- //index.json
- {
- "navigationBarTitleText": "首页",
- "usingComponents": {
- "loading": "/components/Loading/loading"//引用组件
- }
- }
- //index.js
- const app = getApp()
- let loadingMore = false
- let lastScollTop = 0;
- let lastRequestTime = 0;
- Page({
- data: {
- list: [],
- hasMore: true,//列表是否有数据未加载
- page: 1,
- size: 8,//每页8条数据
- scrollYHeight: 0,//scroll-view高度
- },
- bindscroll: function (e) {
- const { scrollHeight, scrollTop } = e.detail;
- const { scrollYHeight, hasMore } = this.data;
- //如果当前没有加载中且列表还有数据未加载,且页面滚动到距离底部40px内
- if (!loadingMore && hasMore && (scrollHeight - scrollYHeight - scrollTop < 40) && lastScollTop <= scrollTop) {
- this.loadMore()
- }
- lastScollTop = scrollTop
- },
- loadMore: function () {
- const { page, hasMore } = this.data;
- if (!hasMore || loadingMore) return;
- loadingMore = true
- setTimeout(
- () => {
- this.fetchList(page + 1, () => {
- loadingMore = false;
- })
- }, 333
- )
- },
- fetchList: function (page, cb) {
- let nowRequestTime = (new Date()).getTime();
- //限制两次网络请求间隔至少1秒
- if (nowRequestTime - lastRequestTime < 1000) {
- if (cb) cb();
- return;
- }
- lastRequestTime = nowRequestTime
- //这里wx.requestTest实际使用时换成wx.request
- //wx.requestTest定义见app.js
- wx.requestTest({
- url: "testUrl",
- header: {
- 'Authorization': wx.getStorageSync('token')
- },
- data: {
- page,
- size: this.data.size,
- },
- success: (res) => {
- if (res.data && res.data.result) {
- let list = res.data.data.rows || [];
- if (list.length == 0) {
- this.setData({
- hasMore: false,
- page,
- })
- } else {
- this.setData({
- list: this.data.list.concat(list),
- hasMore: list.length == this.data.size,
- page,
- })
- }
- } else {
- wx.showToast({
- title: res.data ? res.data.message : "列表加载失败",
- icon: 'none',
- duration: 1000
- })
- }
- if (cb) {
- cb()
- }
- },
- fail: () => {
- wx.showToast({
- title: "列表加载失败",
- icon: 'none',
- duration: 1000
- })
- if (cb) {
- cb()
- }
- }
- })
- },
- onReady: function () {
- wx.getSystemInfo({
- success: ({ windowHeight }) => {
- this.setData({ scrollYHeight: windowHeight })//设置scrill-view组件的高度为屏幕高度
- }
- })
- },
- onLoad: function () {
- this.fetchList(1)//加载第一页数据
- }
- })
- //index.wxml
- <scroll-view scroll-y style="height:{{scrollYHeight}}px" scroll-top="{{scrollTop}}" bindscroll="bindscroll">
- <view
- class="item"
- wx:for="{{list}}"
- wx:key="id"
- wx:for-index="idx"
- >
- {{item.name}}
- </view>
- <loading visible="{{hasMore}}"></loading>
- </scroll-view>
- //index.css
- .item {
- width: 750rpx;
- height: 200rpx;
- font-size: 40rpx;
- color: black;
- position: relative;
- display: flex;
- align-items: center;
- justify-content: center;
- }
- .item::after{
- content: "";
- position: absolute;
- left: 0;
- right: 0;
- bottom: 0;
- border-bottom: 1rpx solid #eeeeee;
- }
此时运行程序,可查看效果。
整体代码:
- //index.js
- const app = getApp()
- let loadingMore = false
- let lastScollTop = 0;
- let lastRequestTime = 0;
- Page({
- data: {
- list: [],
- hasMore: true,//是否有数据未加载
- page: 1,
- size: 8,
- scrollYHeight: 0,
- },
- bindscroll: function (e) {
- const { scrollHeight, scrollTop } = e.detail;
- const { scrollYHeight, hasMore } = this.data;
- //如果当前没有加载中且列表还有数据未加载,且页面滚动到距离底部40px内
- if (!loadingMore && hasMore && (scrollHeight - scrollYHeight - scrollTop < 40) && lastScollTop <= scrollTop) {
- this.loadMore()
- }
- lastScollTop = scrollTop
- },
- loadMore: function () {
- const { page, hasMore } = this.data;
- if (!hasMore || loadingMore) return;
- loadingMore = true
- setTimeout(
- () => {
- this.fetchList(page + 1, () => {
- loadingMore = false;
- })
- }, 333
- )
- },
- fetchList: function (page, cb) {
- let nowRequestTime = (new Date()).getTime();
- if (nowRequestTime - lastRequestTime < 1000) {
- if (cb) cb();
- return;
- }
- lastRequestTime = nowRequestTime
- //这里wx.requestTest实际使用时换成wx.request
- //wx.requestTest定义见app.js
- wx.requestTest({
- url: "testUrl",
- header: {
- 'Authorization': wx.getStorageSync('token')
- },
- data: {
- page,
- size: this.data.size,
- },
- success: (res) => {
- if (res.data && res.data.result) {
- let list = res.data.data.rows || [];
- if (list.length == 0) {
- if(page == 1){
- this.setData({
- hasMore: false,
- page,
- list: []
- })
- }else {
- this.setData({
- hasMore: false,
- page,
- })
- }
- } else {
- this.setData({
- list: this.data.list.concat(list),
- hasMore: list.length == this.data.size,
- page,
- })
- }
- } else {
- wx.showToast({
- title: res.data ? res.data.message : "列表加载失败",
- icon: 'none',
- duration: 1000
- })
- }
- if (cb) {
- cb()
- }
- },
- fail: () => {
- wx.showToast({
- title: "列表加载失败",
- icon: 'none',
- duration: 1000
- })
- if (cb) {
- cb()
- }
- }
- })
- },
- onReady: function () {
- const { windowWidth, ratio } = app.globalData
- wx.getSystemInfo({
- success: ({ windowHeight, pixelRatio }) => {
- this.setData({ scrollYHeight: windowHeight })
- }
- })
- },
- onLoad: function () {
- this.fetchList(1)
- }
- })
-
- //index.wxml
- <scroll-view scroll-y style="height:{{scrollYHeight}}px" scroll-top="{{scrollTop}}" bindscroll="bindscroll">
- <view
- class="item"
- wx:for="{{list}}"
- wx:key="id"
- wx:for-index="idx"
- >
- {{item.name}}
- </view>
- <loading visible="{{hasMore}}"></loading>
- </scroll-view>
-
- //index.css
- .item {
- width: 750rpx;
- height: 200rpx;
- font-size: 40rpx;
- color: black;
- position: relative;
- display: flex;
- align-items: center;
- justify-content: center;
- }
- .item::after{
- content: "";
- position: absolute;
- left: 0;
- right: 0;
- bottom: 0;
- border-bottom: 1rpx solid #eeeeee;
- }
-
- //app.js
- let serverData = [];
- for(let i = 1; i < 25; i++){
- serverData.push({id:i, name:i})
- }
- App({
- onLaunch: function () {
- wx.requestTest = ({data:{page,size},success}) => {
- setTimeout(
- () => {
- //模拟网络返回请求
- let res = {
- data:{
- data:{
- rows: serverData.slice((page - 1) * size, size + (page - 1) * size)
- },
- result: true,
- }
- }
- console.log(res)
- success(res)
- },1000//模拟网络延迟
- )
- }
- },
- globalData: {
- }
- })
暂时没有
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。