当前位置:   article > 正文

uni-app:商品列表_uniapp商品列表

uniapp商品列表

创建 goodslist 分支

运行如下的命令,基于 master 分支在本地创建 goodslist 子分支,用来开发商品列表相关的功能:

git checkout -b search

 

 

定义请求参数对象

为了方便发起请求获取商品列表的数据,我们要根据接口的要求,事先定义一个请求参数对象

 

  1. data() {
  2. return {
  3. // 请求参数对象
  4. queryObj: {
  5. // 查询关键词
  6. query: '',
  7. // 商品分类Id
  8. cid: '',
  9. // 页码值
  10. pagenum: 1,
  11. // 每页显示多少条数据
  12. pagesize: 10
  13. }
  14. }
  15. }

将页面跳转时携带的参数,转存到 queryObj 对象中:

  1. onLoad(options) {
  2. // 将页面参数转存到 this.queryObj 对象中
  3. this.queryObj.query = options.query || ''
  4. this.queryObj.cid = options.cid || ''
  5. }

 

 

为了方便开发商品分类页面,建议大家通过微信开发者工具,新建商品列表页面的编译模式

 

获取商品列表数据 

在 data 中新增如下的数据节点:

  1. data() {
  2. return {
  3. // 商品列表的数据
  4. goodsList: [],
  5. // 总数量,用来实现分页
  6. total: 0
  7. }
  8. }

在 onLoad 生命周期函数中,调用 getGoodsList 方法获取商品列表数据:

  1. onLoad(options) {
  2. // 调用获取商品列表数据的方法
  3. this.getGoodsList()
  4. }

在 methods 节点中,声明 getGoodsList 方法如下:

  1. methods: {
  2. // 获取商品列表数据的方法
  3. async getGoodsList() {
  4. // 发起请求
  5. const { data: res } = await uni.$http.get('/api/public/v1/goods/search', this.queryObj)
  6. if (res.meta.status !== 200) return uni.$showMsg()
  7. // 为数据赋值
  8. this.goodsList = res.message.goods
  9. this.total = res.message.total
  10. }
  11. }

 渲染商品列表结构

在页面中,通过 v-for 指令,循环渲染出商品的 UI 结构:

  1. <template>
  2. <view>
  3. <view class="goods-list">
  4. <block v-for="(goods, i) in goodsList" :key="i">
  5. <view class="goods-item">
  6. <!-- 商品左侧图片区域 -->
  7. <view class="goods-item-left">
  8. <image :src="goods.goods_small_logo || defaultPic" class="goods-pic"></image>
  9. </view>
  10. <!-- 商品右侧信息区域 -->
  11. <view class="goods-item-right">
  12. <!-- 商品标题 -->
  13. <view class="goods-name">{{goods.goods_name}}</view>
  14. <view class="goods-info-box">
  15. <!-- 商品价格 -->
  16. <view class="goods-price">¥{{goods.goods_price}}</view>
  17. </view>
  18. </view>
  19. </view>
  20. </block>
  21. </view>
  22. </view>
  23. </template>

为了防止某些商品的图片不存在,需要在 data 中定义一个默认的图片:

  1. data() {
  2. return {
  3. // 默认的空图片
  4. defaultPic: 'https://img3.doubanio.com/f/movie/8dd0c794499fe925ae2ae89ee30cd225750457b4/pics/movie/celebrity-default-medium.png'
  5. }
  6. }

并在页面渲染时按需使用:

<image :src="goods.goods_small_logo || defaultPic" class="goods-pic"></image>

美化商品列表的 UI 结构:

  1. .goods-item {
  2. display: flex;
  3. padding: 10px 5px;
  4. border-bottom: 1px solid #f0f0f0;
  5. .goods-item-left {
  6. margin-right: 5px;
  7. .goods-pic {
  8. width: 100px;
  9. height: 100px;
  10. display: block;
  11. }
  12. }
  13. .goods-item-right {
  14. display: flex;
  15. flex-direction: column;
  16. justify-content: space-between;
  17. .goods-name {
  18. font-size: 13px;
  19. }
  20. .goods-price {
  21. font-size: 16px;
  22. color: #c00000;
  23. }
  24. }
  25. }

 

 

把商品 item 项封装为自定义组件

在 components 目录上鼠标右键,选择 新建组件

 

将 goods_list 页面中,关于商品 item 项相关的 UI 结构、样式、data 数据,封装到 my-goods 组件中:

  1. <template>
  2. <view class="goods-item">
  3. <!-- 商品左侧图片区域 -->
  4. <view class="goods-item-left">
  5. <image :src="goods.goods_small_logo || defaultPic" class="goods-pic"></image>
  6. </view>
  7. <!-- 商品右侧信息区域 -->
  8. <view class="goods-item-right">
  9. <!-- 商品标题 -->
  10. <view class="goods-name">{{goods.goods_name}}</view>
  11. <view class="goods-info-box">
  12. <!-- 商品价格 -->
  13. <view class="goods-price">{{goods.goods_price}}</view>
  14. </view>
  15. </view>
  16. </view>
  17. </template>
  18. <script>
  19. export default {
  20. // 定义 props 属性,用来接收外界传递到当前组件的数据
  21. props: {
  22. // 商品的信息对象
  23. goods: {
  24. type: Object,
  25. defaul: {},
  26. },
  27. },
  28. data() {
  29. return {
  30. // 默认的空图片
  31. defaultPic: 'https://img3.doubanio.com/f/movie/8dd0c794499fe925ae2ae89ee30cd225750457b4/pics/movie/celebrity-default-medium.png',
  32. }
  33. },
  34. }
  35. </script>
  36. <style lang="scss">
  37. .goods-item {
  38. display: flex;
  39. padding: 10px 5px;
  40. border-bottom: 1px solid #f0f0f0;
  41. .goods-item-left {
  42. margin-right: 5px;
  43. .goods-pic {
  44. width: 100px;
  45. height: 100px;
  46. display: block;
  47. }
  48. }
  49. .goods-item-right {
  50. display: flex;
  51. flex-direction: column;
  52. justify-content: space-between;
  53. .goods-name {
  54. font-size: 13px;
  55. }
  56. .goods-price {
  57. font-size: 16px;
  58. color: #c00000;
  59. }
  60. }
  61. }
  62. </style>

 在 goods_list 组件中,循环渲染 my-goods 组件即可:

  1. <view class="goods-list">
  2. <block v-for="(item, i) in goodsList" :key="i">
  3. <!-- 为 my-goods 组件动态绑定 goods 属性的值 -->
  4. <my-goods :goods="item"></my-goods>
  5. </block>
  6. </view>

 

 

使用过滤器处理价格

在 my-goods 组件中,和 data 节点平级,声明 filters 过滤器节点如下:

  1. filters: {
  2. // 把数字处理为带两位小数点的数字
  3. tofixed(num) {
  4. return Number(num).toFixed(2)
  5. }
  6. }

在渲染商品价格的时候,通过管道符 | 调用过滤器:

  1. <!-- 商品价格 -->
  2. <view class="goods-price">{{goods.goods_price | tofixed}}</view>

 

 

上拉加载更多

初步实现上拉加载更多

打开项目根目录中的 pages.json 配置文件,为 subPackages 分包中的 goods_list 页面配置上拉触底的距离:

  1. "subPackages": [
  2. {
  3. "root": "subpkg",
  4. "pages": [
  5. {
  6. "path": "goods_detail/goods_detail",
  7. "style": {}
  8. },
  9. {
  10. "path": "goods_list/goods_list",
  11. "style": {
  12. "onReachBottomDistance": 150
  13. }
  14. },
  15. {
  16. "path": "search/search",
  17. "style": {}
  18. }
  19. ]
  20. }
  21. ]

在 goods_list 页面中,和 methods 节点平级,声明 onReachBottom 事件处理函数,用来监听页面的上拉触底行为:

  1. // 触底的事件
  2. onReachBottom() {
  3. // 让页码值自增 +1
  4. this.queryObj.pagenum += 1
  5. // 重新获取列表数据
  6. this.getGoodsList()
  7. }

改造 methods 中的 getGoodsList 函数,当列表数据请求成功之后,进行新旧数据的拼接处理:

  1. // 获取商品列表数据的方法
  2. async getGoodsList() {
  3. // 发起请求
  4. const { data: res } = await uni.$http.get('/api/public/v1/goods/search', this.queryObj)
  5. if (res.meta.status !== 200) return uni.$showMsg()
  6. // 为数据赋值:通过展开运算符的形式,进行新旧数据的拼接
  7. this.goodsList = [...this.goodsList, ...res.message.goods]
  8. this.total = res.message.total
  9. }

 

 

[...this.goodsList,...res.message.goods] 让新的数据放在旧的数据后面

通过节流阀防止发起额外的请求

在 data 中定义 isloading 节流阀如下:

  1. data() {
  2. return {
  3. // 是否正在请求数据
  4. isloading: false
  5. }
  6. }

修改 getGoodsList 方法,在请求数据前后,分别打开和关闭节流阀:

  1. // 获取商品列表数据的方法
  2. async getGoodsList() {
  3. // ** 打开节流阀
  4. this.isloading = true
  5. // 发起请求
  6. const { data: res } = await uni.$http.get('/api/public/v1/goods/search', this.queryObj)
  7. // ** 关闭节流阀
  8. this.isloading = false
  9. // 省略其它代码...
  10. }

在 onReachBottom 触底事件处理函数中,根据节流阀的状态,来决定是否发起请求:

  1. // 触底的事件
  2. onReachBottom() {
  3. // 判断是否正在请求其它数据,如果是,则不发起额外的请求
  4. if (this.isloading) return
  5. this.queryObj.pagenum += 1
  6. this.getGoodsList()
  7. }

判断数据是否加载完毕

如果下面的公式成立,则证明没有下一页数据了:

  1. 当前的页码值 * 每页显示多少条数据 >= 总数条数
  2. pagenum * pagesize >= total

修改 onReachBottom 事件处理函数如下:

  1. // 触底的事件
  2. onReachBottom() {
  3. // 判断是否还有下一页数据
  4. if (this.queryObj.pagenum * this.queryObj.pagesize >= this.total) return uni.$showMsg('数据加载完毕!')
  5. // 判断是否正在请求其它数据,如果是,则不发起额外的请求
  6. if (this.isloading) return
  7. this.queryObj.pagenum += 1
  8. this.getGoodsList()
  9. }

 

 

下拉刷新

在 pages.json 配置文件中,为当前的 goods_list 页面单独开启下拉刷新效果:

  1. "subPackages": [{
  2. "root": "subpkg",
  3. "pages": [{
  4. "path": "goods_detail/goods_detail",
  5. "style": {}
  6. }, {
  7. "path": "goods_list/goods_list",
  8. "style": {
  9. "onReachBottomDistance": 150,
  10. "enablePullDownRefresh": true,
  11. "backgroundColor": "#F8F8F8"
  12. }
  13. }, {
  14. "path": "search/search",
  15. "style": {}
  16. }]
  17. }]

监听页面的 onPullDownRefresh 事件处理函数:

  1. // 下拉刷新的事件
  2. onPullDownRefresh() {
  3. // 1. 重置关键数据
  4. this.queryObj.pagenum = 1
  5. this.total = 0
  6. this.isloading = false
  7. this.goodsList = []
  8. // 2. 重新发起请求
  9. this.getGoodsList(() => uni.stopPullDownRefresh())
  10. }

修改 getGoodsList 函数,接收 cb 回调函数并按需进行调用:

  1. // 获取商品列表数据的方法
  2. async getGoodsList(cb) {
  3. this.isloading = true
  4. const { data: res } = await uni.$http.get('/api/public/v1/goods/search', this.queryObj)
  5. this.isloading = false
  6. // 只要数据请求完毕,就立即按需调用 cb 回调函数
  7. cb && cb()
  8. if (res.meta.status !== 200) return uni.$showMsg()
  9. this.goodsList = [...this.goodsList, ...res.message.goods]
  10. this.total = res.message.total
  11. }

 

 

点击商品 item 项跳转到详情页面

将循环时的 block 组件修改为 view 组件,并绑定 click 点击事件处理函数:

  1. <view class="goods-list">
  2. <view v-for="(item, i) in goodsList" :key="i" @click="gotoDetail(item)">
  3. <!-- 为 my-goods 组件动态绑定 goods 属性的值 -->
  4. <my-goods :goods="item"></my-goods>
  5. </view>
  6. </view>

 block 不支持绑定click电视事件

在 methods 节点中,定义 gotoDetail 事件处理函数:

  1. // 点击跳转到商品详情页面
  2. gotoDetail(item) {
  3. uni.navigateTo({
  4. url: '/subpkg/goods_detail/goods_detail?goods_id=' + item.goods_id
  5. })
  6. }

 

 

分支的合并与提交

将 goodslist 分支进行本地提交:

  1. git add .
  2. git commit -m "完成了商品列表页面的开发"

将本地的 goodslist 分支推送到码云:

git push -u origin goodslist

 将本地 goodslist 分支中的代码合并到 master 分支:

  1. git checkout master
  2. git merge goodslist
  3. git push

删除本地的 goodslist 分支:

git branch -d goodslist

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Guff_9hys/article/detail/779383
推荐阅读
相关标签
  

闽ICP备14008679号