• 微信小程序 ---- 慕尚花坊 商品管理


    商品管理

    01. 配置商品管理分包

    思路分析:

    随着项目功能的增加,项目体积也随着增大,从而影响小程序的加载速度,影响用户的体验。

    因此我们需要将 商品列表商品详情 功能配置成一个分包,

    当用户在访问设置页面时,还预先加载 商品列表商品详情 所在的分包

    在分包后,通过查看代码依赖查看是否分包完成

    📌 注意事项

    1. 在配置好 商品列表商品详情 的分包以后,需要更改页面中的跳转路径
    2. PS:可以利用项目全局搜索的功能,进行批量更改

    实现步骤:

    1. modules 目录下创建 goodModule 文件夹,用来存放商品管理分包
    2. app.jsonsubpackages 进行商品管理分包配置
    3. app.jsonpreloadRule 进行商品管理分包配置

    落地代码:

    ➡️ app.json

    {
      "subPackages": [
        {
          "root": "modules/settingModule",
          "name": "settingModule",
          "pages": [
            "pages/address/add/index",
            "pages/address/list/index",
            "pages/profile/profile"
          ]
        },
    +     {
    +       "root": "modules/goodModule",
    +       "name": "goodModule",
    +       "pages": ["pages/goods/list/list", "pages/goods/detail/detail"]
        }
      ],
      "preloadRule": {
        "pages/settings/settings": {
          "network": "all",
          "packages": ["settingModule"]
        },
    +     "pages/category/category": {
    +       "network": "all",
    +       "packages": ["goodModule"]
    +     }
      }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    02. 封装商品模块接口 API

    思路分析:

    为了方便后续进行商品管理模块的开发,我们在这一节将商品管理所有的接口封装成接口 API 函数

    落地代码:

    ➡️ api/goods.js

    import http from '../utils/http'
    
    /**
     * @description 获取商品列表
     * @return Promise
     */
    export const reqGoodsList = ({ limit, page, ...reset }) => {
      return http.get(`/mall-api/goods/list/${page}/${limit}`, reset)
    }
    
    /**
     * @description 获取商品详情
     * @param {*} goodsId 商品Id
     * @returns Promise
     */
    export const reqGoodsInfo = (goodsId) => {
      return http.get(`/mall-api/goods/${goodsId}`)
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    03. 商品列表-准备列表请求参数

    思路分析:

    当用户点击了商品分类以后,需要获取对应分类的商品列表信息,因此我们需要先获取到该分类的 id,只要获取到 id 以后,才能向服务器获取对应分类的商品列表信息。同时我们需要查看接口文档,查看是否需要使用其他参数,我们提前将参数准备好。

    首先熟悉接口文档:获取商品分页列表

    参数名称参数说明是否必须
    limit每页记录数true
    page当前页码true
    category1Id一级分类的 Id (从首页导航分类区域点击进入)false
    category2Id二级分类的 Id (从分类页面点击进入二级分类进入)false

    通过接口文档得知,我们需要以上的参数,我们先将参数提前声明,然后在发起请求获取商品列表的数据

    实现步骤:

    1. 在商品列表的 data 字段中,根据接口文档,定义商品列表接口需要使用的字段
    2. 在商品列表的 onLoad 钩子函数中接收请求的参数,并将请求参数进行合并

    落地代码:

    ➡️ /modules/goodsModule/pages/list/list.js

    Page({
      // 页面的初始数据
      data: {
        goodsList: [], // 商品列表数据
        isFinish: false, // 判断数据是否加载完毕
    
    +     // 接口请求参数
    +     requestData: {
    +       page: 1, // 页码
    +       limit: 10, // 每页请求多少条数据
    +       category1Id: '', // 一级分类 id
    +       category2Id: '' // 二级分类 id
    +     }
      },
    
    +     // 生命周期函数--监听页面加载
    +     onLoad(options) {
    +       // 接收传递的参数
    +       Object.assign(this.data.requestData, options)
    +     }
    })
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    04. 商品列表-获取商品列表数据并渲染

    思路分析:

    在准备商品列表的请求参数以后,

    在页面调用 API 函数获取商品列表的数据,在获取到数据以后,使用后端返回的数据对页面进行渲染。

    实现步骤:

    1. /pages/goods/list/list.js 中导入封装好的获取商品列表的 API 函数
    2. 页面数据在页面加载的时候进行调用,在 onLoad 钩子函数中调用 reqGoodsList 方法
    3. 在获取到数据以后,使用后端返回的数据对页面进行渲染

    落地代码:

    ➡️ /modules/goodsModules/pages/list/list.js

    + import { reqGoodsList } from '../../../../../api/good'
    
    Page({
      // 页面的初始数据
      data: {
        goodsList: [], // 商品列表数据
    +     total: 0, // 数据总条数
        isFinish: false, // 判断数据是否加载完毕
        // 接口请求参数
        requestData: {
          page: 1, // 页码
          limit: 10, // 每页请求多少条数据
          category1Id: '', // 一级分类 id
          category2Id: '' // 二级分类 id
        }
      },
    
    +   // 获取商品列表的数据
    +   async getGoodsList() {
    +     // 调用 API 获取数据
    +     const { data } = await reqGoodsList(this.data.requestData)
    + 
    +     // 将返回的数据赋值给 data 中的变量
    +     this.setData({
    +       goodsList: data.records,
    +       total: data.total
    +     })
    +   },
    
      // 生命周期函数--监听页面加载
      onLoad(options) {
        // 接收传递的参数
        Object.assign(this.data.requestData, options)
    
    +    // 获取商品列表的数据
    +    this.getGoodsList()
      }
    })
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    ➡️ /modules/goodsModule/pages/list/list.wxml

    
    <view class="container">
      
    +   <view class="goods-list" wx:if="{{ goodsList.length }}">
    +     <block wx:for="{{ goodsList }}" wx:key="id">
    +       <goods-card goodItem="{{ item }}">goods-card>
    +     block>
    
        
        <view class="finish" hidden="{{ !isFinish }}">数据加载完毕~~~view>
      view>
    
    +   
    +   <van-empty wx:else description="该分类下暂无商品,去看看其他商品吧~">
    +     <van-button round type="danger" class="bottom-button" bindtap="gotoBack">
    +       查看其他商品
    +     van-button>
    +   van-empty>
    view>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    05. 商品列表-实现上拉加载更多功能

    思路分析:

    当用户从下向上滑动屏幕时,需要加载更多的商品数据。

    首先需要在 .js 文件中声明 onReachBottom 方法监听用户是否进行了上拉

    当用户上拉时,需要对 page 页码进行加 1,代表要请求下一页的数据

    当参数发生改变后,需要重新发送请求,拿最新的 page 向服务器发送请求获取数据。

    在下一页的商品数据返回以后,将最新的数据和之前的数据进行合并

    实现步骤:

    1. list.js 文件中声明 onReachBottom 事件处理函数,监听用户的上拉行为
    2. onReachBottom 函数中加 page 进行加 1 的操作,同时发送请求获取下一页数据
    3. getGoodsList 函数中,实现参数的合并

    落地代码:

    ➡️ /modules/goodsModule/pages/list/list.js

    import { reqGoodsList } from '../../../api/goods'
    
    Page({
    
      // coding...
    
      // 获取商品列表的数据
      async getGoodsList() {
        // 调用 API 获取数据
        const { data } = await reqGoodsList(this.data.params)
    
        // 将返回的数据赋值给 data 中的变量
        this.setData({
    +       goodsList: [...this.data.goodsList, ...data.records],
          total: data.total
        })
      },
    
      // coding...
    
    +   // 监听页面的上拉操作
    +   onReachBottom() {
    +     let { page } = this.data.requestData
    + 
    +     // 页码 + 1
    +     this.setData({
    +       requestData: { ...this.data.requestData, page: page + 1 }
    +     })
    + 
    +     // 重新发送请求
    +     this.getGoodsList()
    +   }
    
    })
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    06. 商品列表-判断数据是否加载完毕

    思路分析:

    上一节我们实现了上拉加载功能。

    在这一节,我们需要相关的优化:判断数据是否已经加载完,如果加载已经加载完毕,需要给用户进行提示。

    如何判断数据是否加载完成 ❓

    可以使用后端返回的 totalgoodsList 进行对比,如果 total 大于等于 goodsList ,说明商品列表数据没有加载完,可以继续上拉加载更多。

    在模板中,我们通过 totalgoodsList 进行对比,决定是否展示对应的文案

    实现步骤:

    1. 在数据返回以后,将数据中的 total 赋值给 data 中的变量 total
    2. onReachBottom 中进行 totalgoodsList 进行对比
    3. 模板中使用 totalgoodsList 进行对比

    落地代码:

    ➡️ /modules/goodsModule/pages/list/list.js

    import { reqGoodsList } from '../../../api/goods'
    
    Page({
        
      // coding...
        
      // 监听页面的上拉操作
      onReachBottom() {
    +     // 从 data 中解构数据
    +     const { total, goodsList, requestData } = this.data
    +     let { page } = requestData
    + 
    +     // 判断数据是否加载完毕
    +     if (total === goodsList.length) {
    +       // 如果相等,数据数据加载完毕
    +       // 如果数据加载完毕,需要给用户提示,同时不继续加载下一个数据
    +       this.setData({
    +         isFinish: true
    +       })
    + 
    +       return
    +     }
    
        // 页码 + 1
        this.setData({
          requestData: { ...this.data.requestData, page: (page += 1) }
        })
    
        // 重新发送请求
        this.getGoodsList()
      }
    })
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    07. 商品列表-节流阀进行列表节流

    在用户网速很慢的情况下,如果用户在距离底部来回的进行多次滑动,可能会发送一些无意义的请求、造成请求浪费的情况,因此需要给上拉加载添加节流功能。

    我们使用节流阀来给商品列表添加节流功能。

    data 中定义节流阀状态 isLoading,默认值是 false

    在请求发送之前,将 isLoading 设置为 true,表示请求正在发送。

    在请求结束以后,将 isLoading 设置为 false,表示请求已经完成。

    onReachBottom 事件监听函数中,对 isLoading 进行判断,如果数据正在请求中,不请求下一页的数据。

    落地代码:

    ➡️ /modules/goodsModule/pages/list/list.js

    import { reqGoodsList } from '../../../../../api/good'
    
    Page({
      // 页面的初始数据
      data: {
        goodsList: [], // 商品列表数据
        isFinish: false, // 判断数据是否加载完毕
    +     isLoading: false, // 判断数据是否记载完毕
        total: 0, // 列表总数据量
        // 接口请求参数
        requestData: {
          page: 1, // 页码
          limit: 10, // 每页请求多少条数据
          category1Id: '', // 一级分类 id
          category2Id: '' // 二级分类 id
        }
      },
    
      // 获取商品列表的数据
      async getGoodsList() {
    +     // 数据真正请求中
    +     this.data.isLoading = true
    
        // 调用 API 获取数据
        const { data } = await reqGoodsList(this.data.requestData)
    
    +     // 数据加载完毕
    +     this.data.isLoading = false
    
        // 将返回的数据赋值给 data 中的变量
        this.setData({
          goodsList: [...this.data.goodsList, ...data.records],
          total: data.total
        })
      },
    
      // 监听页面的上拉操作
      onReachBottom() {
        // 从 data 中解构数据
        const { total, goodsList, requestData, isLoading } = this.data
        let { page } = requestData
    
    +    // 判断是否加载完毕,如果 isLoading 等于 true
    +    // 说明数据还没有加载完毕,不加载下一页数据
    +    if (isLoading) return
    
        // 判断数据是否加载完毕
        // coding...
      }
    })
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    08. 商品列表-实现下拉刷新功能

    下拉刷新是小程序中常见的一种刷新方式,当用户下拉页面时,页面会自动刷新,以便用户获取最新的内容。

    小程序中实现上拉加载更多的方式:

    1. 页面.json 中开启允许下拉,同时可以配置 窗口、loading 样式等

    2. 页面.js 中定义 onPullDownRefresh 事件监听用户下拉刷新

    落地代码:

    ➡️ /modules/goodsModule/pages/list/list.json

    {
      "usingComponents": {
        "goods-card": "/components/goods-card/goods-card"
      },
    
      "navigationBarTitleText": "商品列表",
      "enablePullDownRefresh": true,
      "backgroundColor": "#f7f4f8",
      "backgroundTextStyle": "dark"
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    ➡️ /modules/goodsModule/pages/list/list.js

    // 监听页面的下拉刷新
    onPullDownRefresh() {
      // 将数据进行重置
      this.setData({
        goodsList: [],
        total: 0,
        isFinish: false,
        requestData: { ...this.data.requestData, page: 1 }
      })
    
      // 重新获取列表数据
      this.getGoodsList()
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    09. 商品详情-获取并渲染商品详情

    思路分析:

    点击首页轮播图以及点击商品列表商品的时候,需要跳转到商品详情页面

    在跳转时将商品的id 传递到了商品详情页面,只需要使用 id 向后端服务器请求数据,获取对应商品的详情数据

    在获取到数据以后,使用后端返回的数据对页面进行渲染。

    实现步骤:

    1. /pages/goods/detail/detail.js 中导入封装好的获取商品列表的 API 函数
    2. 页面数据在页面加载的时候进行调用,在 onLoad 钩子函数中调用 reqGoodsInfo 方法
    3. 在获取到数据以后,使用后端返回的数据对页面进行渲染

    落地代码:

    ➡️ /modules/goodsModule/pages/detail/detail.js

    + import { reqGoodsInfo } from '../../../api/goods'
    
    Page({
    
      // 页面的初始数据
      data: {
        goodsInfo: {}, // 商品详情
        show: false, // 控制加入购物车和立即购买弹框的显示
        count: 1, // 商品购买数量,默认是 1
        blessing: '' // 祝福语
      },
    
    +   // 获取商品的详情
    +   async getGoodsInfo() {
    +     // 调用接口、传入参数、获取商品详情
    +     const { data: goodsInfo } = await reqGoodsInfo(this.goodsId)
    + 
    +     // 将商品详情数据赋值给 data 中的变量
    +     this.setData({
    +       goodsInfo
    +     })
    +   },
    
    +   // 生命周期函数--监听页面加载
    +   onLoad(options) {
    +     // 将商品 id 挂载到页面实例上
    +     this.goodsId = options.goodsId ? options.goodsId : ''
    + 
    +     // 获取商品详情的数据
    +     this.getGoodsInfo()
    +   }
    
      // coding...
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    ➡️ /modules/goodsModule/pages/detail/detail.html

    <view class="container goods-detail">
      
      <view class="banner-img">
    +     <image class="img" src="{{ goodsInfo.imageUrl }}" />
      view>
    
      
      <view class="content">
        <view class="price">
    +       <view class="price-num">¥{{ goodsInfo.price }}view>
    +       <view class="price-origin-num">¥{{ goodsInfo.marketPrice }}view>
        view>
    +     <view class="title">{{ goodsInfo.name }}view>
    +     <view class="desc">{{ goodsInfo.material }}view>
      view>
    
      
      <view class="detail">
        <image
    +       wx:for="{{ goodsInfo.detailList}}"
    +       wx:key="index"
    +       src="{{ item }}"
          class="img"
          mode="widthFix"
        />
      view>
    
      
      <van-goods-action>
        
      van-goods-action>
    
      
      
      
      <van-action-sheet show="{{ show }}" bind:close="onClose">
        <view class="sheet-wrapper">
          <view class="goods-item">
            
            <view class="mid">
    +           <image class="img" src="{{ goodsInfo.imageUrl }}" />
            view>
    
            
            <view class="right">
              
    +           <view class="title"> {{ goodsInfo.name }} view>
              
              <view class="buy">
                <view class="price">
                  <view class="symbol">¥view>
    +               <view class="num">{{ goodsInfo.price }}view>
                view>
    
                
                <view class="buy-btn">
                  
                  <van-stepper value="{{ count }}" bind:change="onChangeGoodsCount" />
                view>
              view>
            view>
          view>
    
          
          <view class="time-wraper">
            
          view>
    
          
          <view class="sheet-footer-btn">
            <van-button block type="primary" round> 确定 van-button>
          view>
        view>
      van-action-sheet>
    view>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76

    10. 商品详情-详情图片预览功能

    思路分析:

    当点击商品的图片时,需要将图片进行全屏预览

    如果想实现该功能,需要使用小程序提供的 APIwx.previewImage(),用来在新页面中全屏预览图片。预览的过程中用户可以进行保存图片、发送给朋友等操作。语法如下:

    wx.previewImage({
      current: '', // 当前显示图片的 http 链接
      urls: [] // 需要预览的图片 http 链接列表
    })
    
    • 1
    • 2
    • 3
    • 4

    实现步骤:

    1. 给展示大图的 image 组件绑定点击事件,同时通过自定义属性的方式,传递当前需要显示的图片http 链接
    2. 同时商品详情的数组数据传递给 urls 数组即可

    落地代码:

    ➡️ /pages/goods/detail/detail.html

    
    <view class="banner-img">
      <image
         class="img"
         src="{{ goodsInfo.imageUrl }}"
         bindtap="previewImg"
      />
    view>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    ➡️ /pages/goods/detail/detail.js

    // 预览商品图片
    previewImg() {
      // 调用预览图片的 API
      wx.previewImage({
        urls: this.data.goodsInfo.detailList
      })
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    优化:配置 @ 路径别名优化访问路径

    在对小程序进行分包时,如果访问小程序根目录下的文件,那么访问的路径就会很长。

    在 Vue 中,可以使用 @ 符号指向源码目录,简化路径,小程序也给提供了配置的方式。

    在小程序中可以在 app.json 中使用 resolveAlias 配置项用来自定义模块路径的映射规则。

    官方文档: resolveAlias

    {
      "resolveAlias": {
        "@/*": "/*"
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    📌:注意事项:

    1. resolveAlias 进行的是路径匹配,其中的 key 和 value 须以 /* 结尾

    2. 如果在 project.config.json 中指定了 miniprogramRoot,则 /* 指代的根目录是 miniprogramRoot 对应的路径,而不是开发者工具项目的根目录

  • 相关阅读:
    信号量机制实现进程互斥,进程同步,进程的前驱关系
    php生成器
    数字员工|技术与业务双向融合创造更多价值
    IDEA中pom文件出现灰色且有删除的线解决方案
    conda安装与镜像源配置
    环境治理行业标识解析二级节点平台建设解决方案
    【DL论文精读笔记】Object Detection in 20 Years: A Survey目标检测综述
    MySQL(五)增删改查进阶
    docker安装elasticsearch镜像与加载容器
    生命在于折腾——某国外cms代码审计
  • 原文地址:https://blog.csdn.net/qq_63358859/article/details/136388716