微信小程序实战之书写一个完整的数据展示页

277 阅读5分钟

我正在参加「掘金·启航计划」

前言

这是我参加掘金启航计划的第一篇文章,主要总结一些微信小程序开发常见的写法,如页面下拉刷新、分页、页面无数据展示提示信息等操作。

本篇文章基于 微信云开发 ,数据从云数据库中取出,使用微信云数据API进行获取数据。

相信看完之后就可以完整的写出一个列表 展示页 了,希望观众老爷们多多支持!

1. 书写API

首先我们需要在云开发数据库中创建一个集合 modes ,用于储存我们的数据。

image.png

然后我们在项目根目录下创建一个 utils 文件夹,分别创建 apidatabase 文件夹:

  • api 文件夹用于存储我们对外部 API 的封装,如请求外部接口,远程服务器的服务接口。
  • database 文件夹用于存储我们操作云数据库集合的方法。

image.png

为什么要这样写呢?

以前我的写法是:直接在页面中使用微信操作云数据库的API进行获取数据,但这样不易于代码的维护和重用,所以采用上述的写法。

再之我们在 database 文件夹中创建 modes.js 文件,用于书写我们针对 modes 集合操作的方法,写入以下代码:

import dayjs from "dayjs"; //dayjs库 对时间进行处理

const _ = wx.cloud.database().command;

function table(name) {
    return wx.cloud.database().collection(name);
}

/**
 * 获取模板数据的分页列表
 * @param {number} num 数据截取点
 * @param {number} begin 起始页
 */
async function getModes(num, begin) {
    const {
        data
    } = await table("modes").where({
        'flog': true
    }).
    orderBy("useNum", "desc"). // 按照useNum 使用数量进行升序排列
    limit(num). // limit 截取
    skip(begin). 
    get();
    return data;
}

/**
 * 获取模板库数据的总数
 */
async function getModesTotal() {
    const {total} = await table("modes").where({
        'flog': true
    }).count();
    return total;
}

//向外部暴露这些方法
export {
    getModes,
    getModesTotal
}

上述方法中JS代码中的'flog': true条件,用于判断该数据是否被删除,flog为true没有被删除。

2. 创建页面并进行配置

通过 app.json 配置文件,创建 modes 页面后,在 modes.json 配置下拉刷新,上拉触底。

{
  "enablePullDownRefresh": true, 
  "onReachBottomDistance": 50   
}

3. 书写分页代码,进行数据展示

首先在 modes.js 文件中的 data 中书写以下数据名:

data: {
        modesList: [],
        isLoading: false, //节流阀,
        pageNum: 1,
        pages: 0,
        isToast: false,
        loadingText:'加载中...',
        isPull:false,
    },

这些数据名的含义,在后续代码中解释。

然后在 modes.js 引入第一节中的 database/modes 文件中两个封装后的API方法:

// pakA/pages/modes/modes.js

import {
    getModes,
    getModesTotal
} from '../../../utils/database/modes.js'

Page({

再之,在 Page 方法中书写我们进行分页的方法 getModeList ,该方法会综合我们引入的两个 API

/**
 * 分页函数
 * @param {number} pageNum 起始页 默认从第一页开始
 * @param {number} num 每页的数据列表项个数 默认一页4个列表项
*/
async getModeList(pageNum = 1, num = 4) {
        if (!this.data.isLoading) { // 1
            this.setData({
                'isLoading': true  // 1
            });
            let total = await getModesTotal(); // 2
            let add = total % num > 0 ? 1 : 0; // 2 
            let pages = parseInt(total / num) + add; // 2
            this.setData({ 
                'pages':pages // 2
            });
            let begin = (pageNum - 1) * num; // 2
            let temp = await getModes(num, begin); // 3
            this.setData({ // 3
                'modesList': [
                    ...this.data.modesList,
                    ...temp
                ]
            })
            this.setData({
                'isLoading': false  // 1
            });
        }
    }

对这段代码进行解释:

  1. 标记点1:为什么要判断 data 中的 isLoading ,主要是起到一个节流阀的作用,因为当用户频繁的触底操作时,会发送多个请求;通过使用该标志,可以在上一次请求结束后,再进行下一次操作。也就是当 isLoading=false 才执行条件中的代码,进入后,立即将 isLoading 设置为 ture,在请求结束后,将 isLoading 设置为 false
  2. 标记点2:首先我们需要通过 getModesTotal() 方法获取数据的总数 total;然后通过 add 计算出是否有空余页,有的话,赋值为1,否则为0;然后通过 pages 获取在 num 下的页面总数 pages ,再赋值给 data 中的 pages;最后通过 begin 获取数据截取点。
  3. 标记点3:通过标记点的操作,我们获取 begin ,再使用 getModes() 方法就可以获取分页后的数据了。

最后,在 onLoad 生命周期函数中书写以下代码:用于在打开页面时,获取第一页的数据。

onLoad(options) {
    this.getModeList();
}

之后进行数据的展示,在 modes.wxml 中书写以下代码,进行数据的渲染:

<view class="container">
    <view class="container-card" wx:for="{{modesList}}" wx:key="index"  data-index="{{index}}">
        <view class="container-card-header">
            <view class="left">{{item.modeName}}</view>
            <view class="right" hidden="{{item.userNum != 0}}">{{item.userNum}}人使用</view>
        </view>
        <view class="container-card-content">
            <view class="left">
            <image src="{{item.iconUrl}}"></image>
            </view>
            <view class="right">{{item.description}}</view>
        </view>
        <view class="btn-area">
            <view class="btn" bindtap="chanceMode" data-index="{{index}}">选择</view>
        </view>
    </view>
    <!--用于显示提示信息-->
    <view class="bot-loading" wx:if="{{isLoading}}">加载中...</view>
    <view class="bot-toast" wx:if="{{isToast}}">{{loadingText}}</view>
</view>

首次打开页面就是以下的效果:

image.png

4. 书写下拉刷新代码

下拉刷新是指将页面恢复为初始状态(相当于刚打开页面时的状态)。 在页面 Page 函数中书写 onRefresh 用于将页面恢复初始状态:

onRefresh() {
    this.setData({
        "pageNum": 1,
        'modesList': [],
    });
    this.getModeList();
    wx.stopPullDownRefresh(); // 请求第一页数据后,结束下拉刷新
}

然后在监听用户下拉动作函数中,执行该方法:

/**
 * 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh() {
    this.onRefresh();
}

这样就配置好了下拉刷新🤩

5. 书写上拉触底,加载下一页代码

在页面上拉触底事件的处理函数中书写以下代码:

    /**
     * 页面上拉触底事件的处理函数
     */
    onReachBottom() {
        this.setData({
            'isToast':true,
        })
        if (this.data.pageNum < this.data.pages) {
            this.setData({
                'pageNum': this.data.pageNum + 1
            })
            this.getModeList(this.data.pageNum);
            this.setData({
                'isToast':false,
            });
        } else {
           this.setData({
               'loadingText':'— 没有了 —'
           })
        }
    }

以上代码的解释:

  1. 第一行的在上拉触底后,立即将 isToast 设置为 true 将会在页面中展示提示信息:
<!--loadingText 默认为 加载中... -->
<view class="bot-toast" wx:if="{{isToast}}">{{loadingText}}</view> 
  1. 第二行进行判断当前页面,是否为最后一页;如果为最后一页,就将 loadingText 设置为 -没有了- ,表示没有下一页了。如果不是最后一页,就将 pageNum 加1,请求下一页数据。

6. 最后

由于该文章中示例代码的项目未写完,就不公开了。

最后希望观众老爷们多多支持,错的地方或好的想法可以写在评论区。

拜谢!🥰