小程序demo实践(二)

659 阅读4分钟

「这是我参与2022首次更文挑战的第15天,活动详情查看:2022首次更文挑战

demo实践

小程序demo实践(一)里已经做了首页效果及实现步骤,具体如下:

  • 梳理项目结构
  • 配置导航栏效果
  • 配置tabBar效果
  • 实现轮播图效果
  • 实现九宫格效果
  • 实现图片布局

商铺列表及实现步骤

本篇主要讲商铺列表的效果及实现步骤

  • 页面导航并传参
  • 列表页面的API请求
  • 上拉底部时加载下一页数据
  • 下拉刷新列表数据
  • 使用 wxs 处理手机号

页面导航并传参

  • 创建商铺列表页面

    "pages":[
        "pages/home/home",
        "pages/message/message",
        "pages/contact/contact",
        "pages/shopList/shopList"
    ],
    
  • 将九宫格 view 改造成 navigator,点击九宫格的每一项将相应的值从首页传到商铺列表页

    <view class="grid-list">
        <navigator class="grid-item" wx:for="{{gridList}}" wx:key="id" url="/pages/shopList/shopList?id={{item.id}}&title={{item.name}}" >
            <image src="{{item.icon}}"></image>
            <text>{{item.name}}</text>
        </navigator>
    </view>
    
  • 设置商铺页面的标题

    设置标题有俩种方式

    • .json 文件中设置页面标题,这种方式设置标题是不可以修改的

      {
          "usingComponents": {},
          "navigationBarTitleText": "美食"
      }
      
    • 动态设置标题,通过 API 设置(动态设置标题需要在生命周期函数的 onReady() 中调用)

      wx.setNavigationBarTitle({
          title: this.data.query.title
      })
      

    设置页面标题

    Page({
    
        //定义一个全局变量
        data: {
            query:{}
        },
        
        //读取传参,并转存全局变量
        onLoad: function (options) {
            this.setData({
                query:options
            })
        },
        
        //设置标题
        onReady: function () {
            wx.setNavigationBarTitle({
                title: this.data.query.title,
            })
        }
    })
    

列表页面的分页API请求

以分页的形式,加载指定分类下的商铺列表的数据

  • 接口地址
  • 请求方式
    • GET 请求
  • 请求参数
    • _page 表示请求第几页的数据

    • _limit 表示每页请求几条数据

页面数据

Page({
    data: {
        query:{},
        //商铺列表
        shopList:[],
        //分页码
        page:1,
        //分页下载量
        pageSize:10,
        //总条数
        total:0
    },

    getShopList(){
    
        //添加loading框
        wx.showLoading({
            title: '数据加载中...',
        })
        
        wx.request({
            url: `https://www.escook.cn/categories/${this.data.query.id}/shops`,
            method: "GET",
            data: {
                _page:this.data.page,
                _limit:this.data.pageSize
            },
            success: (res) => {
                console.log(res)
                this.setData({
                    shopList:[...this.data.shopList,...res.data],
                    total: res.header["X-Total-Count"] - 0
                })
            },
            complete: () => {
                wx.hideLoading()
            }
        })
    },
    
    onLoad: function (options) {
        this.setData({
            query:options
        })
        
        //下载商铺列表
        this.getShopList()
    },

    onReady: function () {
        wx.setNavigationBarTitle({
            title: this.data.query.title,
        })

    }
})

页面结构

<view class="shop-item" wx:for="{{shopList}}" wx:key="id">
    <view class="tumb">
        <image src="{{item.images[0]}}"></image>
    </view>
    <view class="info">
        <text class="shopTitle">{{item.name}}</text>
        <text>电话:{{item.phone}}</text>
        <text>地址:{{item.address}}</text>
        <text>营业时间:{{item.businessHours}}</text>
    </view>
</view>

页面美化

.shop-item {
    display: flex;
    padding: 15rpx;
    border: 1rpx solid #efefef;
    border-radius: 9rpx;
    margin: 15rpx;
    box-shadow: 1rpx 1rpx 15rpx #dddddd;
}

.tumb image {
    width: 250rpx;
    height: 250rpx;
    display: block;
    margin-right: 15rpx;
}

.info {
    display: flex;
    flex-direction: column;
    justify-content: space-around;
    font-size: 24rpx;
}

.shopTitle {
    font-weight: bold;
}

上拉底部时加载下一页数据

  • 设置上拉触底的距离

    在商铺页面的 .json 文件中设置触底距离

    {
        "usingComponents": {},
        "onReachBottomDistance": 200
    }
    
  • 上拉触底事件中,分页码自增。再次调用下载商铺信息的接口

    onReachBottom: function () {
        
        this.setData({
            page: this.data.page + 1
        })
        
        this.getShopList()
    },
    
  • 通过节流阀,控制频繁、反复的上拉刷新

    data: {
        //其他属性。。。
        
        //定义请求节流阀
        isloading:false
    },
    
    getShopList(){
    
        //变更节流阀状态
        this.setData({
            isloading: true
        })
        //添加loading框
        wx.showLoading({
            title: '数据加载中...',
        })
        
        wx.request({
        
            //其他代码。。
            
            complete: () => {
                wx.hideLoading()
                
                //变更节流阀状态
                this.setData({
                    isloading: false
                })
            }
        })
    },
    
    onReachBottom: function () {
        //判断节流阀状态
        if (this.data.isloading) return
        
        this.setData({
            page: this.data.page + 1
        })
        
        this.getShopList()
    },
    
  • 判断是否还有下一页数据

    服务器返回数据总数是80条,如果不做处理,继续执行上拉刷新,那么服务器每次返回的数据为空,为了解决不必要的请求,可以根据数据总数判断是否继续执行数据请求

    公式:页码值 * 每页显示多少条数据 >= 总数据条数

    判断是否是有下一页数据并弹框说明(调用系统 wx.showToast()

    onReachBottom: function () {
    
        if (this.data.isloading) return
        
        if (this.data.page * this.data.pageSize >= this.data.total){
        
            //证明没有下一页了
            return wx.showToast({
                title: '数据加载完毕!',
                icon: "none"
            })
        }
    }
    

下拉刷新列表数据

  • 设置页面支持下拉刷新

    在商铺页面的 .json 文件中设置触底距离

    {
    
    "usingComponents": {},
    "onReachBottomDistance": 200,
    "enablePullDownRefresh": true,
    
    "backgroundColor": "#efefef",
    "backgroundTextStyle": "dark"
    }
    
  • 下拉刷新事件中,重置某些关键值。再次调用下载商铺信息的接口

    onPullDownRefresh: function () {
        
        //重置数据值
        this.setData({
            page: 1,
            shopList: [],
            total:0
        })
    
        //重新发请求
        this.getShopList()
    },
    
  • 下拉刷新之后,关闭下拉刷新的状态

    • 通过给 getShopList() 函数设置回调,判断关闭下拉刷新
getShopList(cb){
    
    //其他代码。。。
    
    //请求完成
    complete: () => {
        wx.hideLoading()
    
        this.setData({
            isloading: false
        })
        
        cb && cb()
    }
}


onPullDownRefresh: function () {
    this.setData({
        page: 1,
        shopList: [],
        total:0
    })
    
    //重新请求是将回调函数传入
    this.getShopList(() => {
        //停止下拉刷新
        wx.stopPullDownRefresh()
    })
},

使用 wxs 处理手机号

  • 新建 .wxs 文件

    //将手机号格式 13910733521 改为 139-1073-3521
    function splitPhone(str){
    
        //判断手机号是否是11位
        if (str.length != 11) return str
        
        var arr = str.split("")
        arr.splice (3,0,"-")
        arr.splice (8,0,"-")
        return arr.join("")
    }
    
    //导出
    module.exports = {
        splitPhone:splitPhone
    }
    
  • 页面调用

    <view class="shop-item" wx:for="{{shopList}}" wx:key="id">
        <view class="tumb">
            <image src="{{item.images[0]}}"></image>
        </view>
        <view class="info">
            <text class="shopTitle">{{item.name}}</text>
            <text>电话:{{tools.splitPhone(item.phone)}}</text>
            <text>地址:{{item.address}}</text>
            <text>营业时间:{{item.businessHours}}</text>
        </view>
    </view>
    
    <!-- 导入tools -->
    <wxs src="../../utils/tools.wxs" module="tools"></wxs>