【 uniapp - 黑马优购 | 商品列表 】如何实现数据获取、结构渲染、自定义组件的封装

news2024/12/23 0:53:19

在这里插入图片描述


在这里插入图片描述


个人名片:

🐼作者简介:一名大二在校生,讨厌编程🎋
🐻‍❄️个人主页🥇:小新爱学习.
🐼个人WeChat:hmmwx53
🕊️系列专栏:🖼️

  • 零基础学Java——小白入门必备
  • 重识C语言——复习回顾
  • 计算机网络体系———深度详讲
  • 微信小程序开发——实战开发
  • 基于黑马优选的小程序开发实战教程

🐓每日一句:🍭努力的意义是给所爱之人一个美好的未来!


文章目录

  • 6. 商品列表
    • 6.0 创建 goodslist 分支
    • 6.1 定义请求参数对象
    • 6.2 获取商品列表数据
    • 6.3 渲染商品列表结构
    • 6.4 把商品 `item` 项封装为自定义组件
    • 6.5 使用过滤器处理价格
    • 6.6 上拉加载更多
      • 6.6.1 初步实现上拉加载更多
      • 6.6.2 通过节流阀防止发起额外的请求
      • 6.6.3 判断数据是否加载完毕
    • 6.7 下拉刷新
    • 6.8 点击商品 item 项跳转到详情页面
    • 6.9 分支的合并与提交


6. 商品列表

6.0 创建 goodslist 分支

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

git checkout -b search

6.1 定义请求参数对象

  1. 为了方便发起请求获取商品列表的数据,我们要根据接口的要求,事先定义一个请求参数对象:
data() {
  return {
    // 请求参数对象
    queryObj: {
      // 查询关键词
      query: '',
      // 商品分类Id
      cid: '',
      // 页码值
      pagenum: 1,
      // 每页显示多少条数据
      pagesize: 10
    }
  }
}
  1. 将页面跳转时携带的参数,转存到 queryObj 对象中:
onLoad(options) {
  // 将页面参数转存到 this.queryObj 对象中
  this.queryObj.query = options.query || ''
  this.queryObj.cid = options.cid || ''
}
  1. 为了方便开发商品分类页面,建议大家通过微信开发者工具,新建商品列表页面的编译模式:

在这里插入图片描述

6.2 获取商品列表数据

  1. data 中新增如下的数据节点:
data() {
  return {
    // 商品列表的数据
    goodsList: [],
    // 总数量,用来实现分页
    total: 0
  }
}
  1. onLoad 生命周期函数中,调用 getGoodsList 方法获取商品列表数据:
onLoad(options) {
  // 调用获取商品列表数据的方法
  this.getGoodsList()
}
  1. methods 节点中,声明 getGoodsList 方法如下:
methods: {
  // 获取商品列表数据的方法
  async getGoodsList() {
    // 发起请求
    const { data: res } = await uni.$http.get('/api/public/v1/goods/search', this.queryObj)
    if (res.meta.status !== 200) return uni.$showMsg()
    // 为数据赋值
    this.goodsList = res.message.goods
    this.total = res.message.total
  }
}

6.3 渲染商品列表结构

  1. 在页面中,通过 v-for 指令,循环渲染出商品的 UI 结构:
<template>
  <view>
    <view class="goods-list">
      <block v-for="(goods, i) in goodsList" :key="i">
        <view class="goods-item">
          <!-- 商品左侧图片区域 -->
          <view class="goods-item-left">
            <image :src="goods.goods_small_logo || defaultPic" class="goods-pic"></image>
          </view>
          <!-- 商品右侧信息区域 -->
          <view class="goods-item-right">
            <!-- 商品标题 -->
            <view class="goods-name">{{goods.goods_name}}</view>
            <view class="goods-info-box">
              <!-- 商品价格 -->
              <view class="goods-price">¥{{goods.goods_price}}</view>
            </view>
          </view>
        </view>
      </block>
    </view>
  </view>
</template>
  1. 为了防止某些商品的图片不存在,需要在 data 中定义一个默认的图片:
data() {
  return {
    // 默认的空图片
    defaultPic: 'https://img3.doubanio.com/f/movie/8dd0c794499fe925ae2ae89ee30cd225750457b4/pics/movie/celebrity-default-medium.png'
  }
}
  1. 并在页面渲染时按需使用:
<image :src="goods.goods_small_logo || defaultPic" class="goods-pic"></image>
  1. 美化商品列表的 UI 结构:
.goods-item {
  display: flex;
  padding: 10px 5px;
  border-bottom: 1px solid #f0f0f0;

  .goods-item-left {
    margin-right: 5px;

    .goods-pic {
      width: 100px;
      height: 100px;
      display: block;
    }
  }

  .goods-item-right {
    display: flex;
    flex-direction: column;
    justify-content: space-between;

    .goods-name {
      font-size: 13px;
    }

    .goods-price {
      font-size: 16px;
      color: #c00000;
    }
  }
}

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

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

在这里插入图片描述
2. 将 goods_list 页面中,关于商品 item 项相关的 UI 结构、样式、data 数据,封装到 my-goods 组件中:

<template>
  <view class="goods-item">
    <!-- 商品左侧图片区域 -->
    <view class="goods-item-left">
      <image :src="goods.goods_small_logo || defaultPic" class="goods-pic"></image>
    </view>
    <!-- 商品右侧信息区域 -->
    <view class="goods-item-right">
      <!-- 商品标题 -->
      <view class="goods-name">{{goods.goods_name}}</view>
      <view class="goods-info-box">
        <!-- 商品价格 -->
        <view class="goods-price">¥{{goods.goods_price}}</view>
      </view>
    </view>
  </view>
</template>

<script>
  export default {
    // 定义 props 属性,用来接收外界传递到当前组件的数据
    props: {
      // 商品的信息对象
      goods: {
        type: Object,
        defaul: {},
      },
    },
    data() {
      return {
        // 默认的空图片
        defaultPic: 'https://img3.doubanio.com/f/movie/8dd0c794499fe925ae2ae89ee30cd225750457b4/pics/movie/celebrity-default-medium.png',
      }
    },
  }
</script>

<style lang="scss">
  .goods-item {
    display: flex;
    padding: 10px 5px;
    border-bottom: 1px solid #f0f0f0;

    .goods-item-left {
      margin-right: 5px;

      .goods-pic {
        width: 100px;
        height: 100px;
        display: block;
      }
    }

    .goods-item-right {
      display: flex;
      flex-direction: column;
      justify-content: space-between;

      .goods-name {
        font-size: 13px;
      }

      .goods-price {
        font-size: 16px;
        color: #c00000;
      }
    }
  }
</style>
  1. goods_list 组件中,循环渲染 my-goods 组件即可:
<view class="goods-list">
  <block v-for="(item, i) in goodsList" :key="i">
    <!-- 为 my-goods 组件动态绑定 goods 属性的值 -->
    <my-goods :goods="item"></my-goods>
  </block>
</view>

6.5 使用过滤器处理价格

  1. my-goods 组件中,和 data 节点平级,声明 filters 过滤器节点如下:
filters: {
  // 把数字处理为带两位小数点的数字
  tofixed(num) {
    return Number(num).toFixed(2)
  }
}
  1. 在渲染商品价格的时候,通过管道符 | 调用过滤器:
<!-- 商品价格 -->
<view class="goods-price">{{goods.goods_price | tofixed}}</view>

6.6 上拉加载更多

6.6.1 初步实现上拉加载更多

  1. 打开项目根目录中的 pages.json 配置文件,为 subPackages 分包中的 goods_list 页面配置上拉触底的距离:
 "subPackages": [
   {
     "root": "subpkg",
     "pages": [
       {
         "path": "goods_detail/goods_detail",
         "style": {}
       },
       {
         "path": "goods_list/goods_list",
         "style": {
           "onReachBottomDistance": 150
         }
       },
       {
         "path": "search/search",
         "style": {}
       }
     ]
   }
 ]
  1. goods_list 页面中,和 methods 节点平级,声明 onReachBottom 事件处理函数,用来监听页面的上拉触底行为:
// 触底的事件
onReachBottom() {
  // 让页码值自增 +1
  this.queryObj.pagenum += 1
  // 重新获取列表数据
  this.getGoodsList()
}
  1. 改造 methods 中的 getGoodsList 函数,当列表数据请求成功之后,进行新旧数据的拼接处理:
// 获取商品列表数据的方法
async getGoodsList() {
  // 发起请求
  const { data: res } = await uni.$http.get('/api/public/v1/goods/search', this.queryObj)
  if (res.meta.status !== 200) return uni.$showMsg()

  // 为数据赋值:通过展开运算符的形式,进行新旧数据的拼接
  this.goodsList = [...this.goodsList, ...res.message.goods]
  this.total = res.message.total
}

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

  1. data 中定义 isloading 节流阀如下:
data() {
  return {
    // 是否正在请求数据
    isloading: false
  }
}
  1. 修改 getGoodsList 方法,在请求数据前后,分别打开和关闭节流阀
// 获取商品列表数据的方法
async getGoodsList() {
  // ** 打开节流阀
  this.isloading = true
  // 发起请求
  const { data: res } = await uni.$http.get('/api/public/v1/goods/search', this.queryObj)
  // ** 关闭节流阀
  this.isloading = false

  // 省略其它代码...
}
  1. onReachBottom 触底事件处理函数中,根据节流阀的状态,来决定是否发起请求:
// 触底的事件
onReachBottom() {
  // 判断是否正在请求其它数据,如果是,则不发起额外的请求
  if (this.isloading) return

  this.queryObj.pagenum += 1
  this.getGoodsList()
}

6.6.3 判断数据是否加载完毕

  1. 如果下面的公式成立,则证明没有下一页数据了:
当前的页码值 * 每页显示多少条数据 >= 总数条数
pagenum * pagesize >= total
  1. 修改 onReachBottom 事件处理函数如下:
// 触底的事件
onReachBottom() {
  // 判断是否还有下一页数据
  if (this.queryObj.pagenum * this.queryObj.pagesize >= this.total) return uni.$showMsg('数据加载完毕!')

  // 判断是否正在请求其它数据,如果是,则不发起额外的请求
  if (this.isloading) return

  this.queryObj.pagenum += 1
  this.getGoodsList()
}

6.7 下拉刷新

  1. pages.json 配置文件中,为当前的 goods_list 页面单独开启下拉刷新效果:
"subPackages": [{
  "root": "subpkg",
  "pages": [{
    "path": "goods_detail/goods_detail",
    "style": {}
  }, {
    "path": "goods_list/goods_list",
    "style": {
      "onReachBottomDistance": 150,
      "enablePullDownRefresh": true,
      "backgroundColor": "#F8F8F8"
    }
  }, {
    "path": "search/search",
    "style": {}
  }]
}]
  1. 监听页面的 onPullDownRefresh 事件处理函数:
// 下拉刷新的事件
onPullDownRefresh() {
  // 1. 重置关键数据
  this.queryObj.pagenum = 1
  this.total = 0
  this.isloading = false
  this.goodsList = []

  // 2. 重新发起请求
  this.getGoodsList(() => uni.stopPullDownRefresh())
}
  1. 修改 getGoodsList 函数,接收 cb 回调函数并按需进行调用:
// 获取商品列表数据的方法
async getGoodsList(cb) {
  this.isloading = true
  const { data: res } = await uni.$http.get('/api/public/v1/goods/search', this.queryObj)
  this.isloading = false
  // 只要数据请求完毕,就立即按需调用 cb 回调函数
  cb && cb()

  if (res.meta.status !== 200) return uni.$showMsg()
  this.goodsList = [...this.goodsList, ...res.message.goods]
  this.total = res.message.total
}

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

  1. 将循环时的 block 组件修改为 view 组件,并绑定 click 点击事件处理函数:
<view class="goods-list">
  <view v-for="(item, i) in goodsList" :key="i" @click="gotoDetail(item)">
    <!-- 为 my-goods 组件动态绑定 goods 属性的值 -->
    <my-goods :goods="item"></my-goods>
  </view>
</view>
  1. methods 节点中,定义 gotoDetail 事件处理函数:
// 点击跳转到商品详情页面
gotoDetail(item) {
  uni.navigateTo({
    url: '/subpkg/goods_detail/goods_detail?goods_id=' + item.goods_id
  })
}

6.9 分支的合并与提交

  1. goodslist 分支进行本地提交:
git add .
git commit -m "完成了商品列表页面的开发"
  1. 将本地的 goodslist 分支推送到码云:
git push -u origin goodslist
  1. 将本地 goodslist 分支中的代码合并到 master 分支:
git checkout master
git merge goodslist
git push
  1. 删除本地的 goodslist 分支:
git branch -d goodslist

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/138939.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

在 Mac 上将 PDF 转换为 Word 的 5 种简单方法

当谈到将PDF格式转换为Word格式时&#xff0c;用户可能会从互联网上搜索并尝试在线将PDF转换为Word。如果是这样&#xff0c;您可能会得到不好的结果并冒着文件本身的风险。在线 PDF 到 Word 转换器工具可能会产生低质量的输出&#xff0c;对文件大小有限制&#xff0c;更糟糕的…

maven多模块依赖版本不一致问题

项目结构&#xff1a; ├─springcloud-alibaba ├─.idea├─shop-common├─shop-order├─shop-product└─shop-user项目环境&#xff1a; 父工程&#xff1a; <properties><spring-cloud.version>Greenwich.RELEASE</spring-cloud.version><sprin…

java虚拟机之垃圾回收机制

一.需要回收的内存区域 程序计数器、虚拟机栈、本地方法栈 3 个区域随线程生灭(因为是线程私有)&#xff0c;栈中的栈帧随着方法的进入和退出而有条不紊地执行着出栈和入栈操作。而 Java 堆和方法区则不一样&#xff0c;一个接口中的多个实现类需要的内存可能不一样&#xff0c…

<Focal Loss for Dense Object Detection>论文解读

目录1.简介2.模型2.1 二阶段要比单阶段模型效果好本质原因2.2 模型结构2.3.focal loss2.3.1 公式说明2.3.2 其他2.4 消融实验3.源码详解1.简介 目标识别有两大经典结构: 第一类是以Faster RCNN为代表的二阶段识别方法&#xff0c;这种结构的第一阶段专注于proposal的提取&am…

后端开发规约

目录 项目MVC层级设计规范 工程项目模块设计 设计规约 Java编码规范 参考《阿里巴巴Java开发手册》&#xff0c;见文末参考文档 OOP 面向对象设计 & 面向接口编程 Lombok工具包依赖 Guava、Hutool 等脚手架工具包&#xff08;三方包使用其一即可&#xff09; 日志打…

python初级教程十 Mongodb增、删、改、查

Mongodb 插入文档 MongoDB 中的一个文档类似 SQL 表中的一条记录。 插入集合 集合中插入文档使用 insert_one() 方法&#xff0c;该方法的第一参数是字典 name > value 对。 以下实例向 sites 集合中插入文档&#xff1a; #!/usr/bin/python3import pymongomyclient p…

03、Java并发 Java 线程池 ( Thread Pool ) (上)

本文我们将讲解 Java 中的线程池 ( Thread Pool )&#xff0c;从 Java 标准库中的线程池的不同实现开始&#xff0c;到 Google 开发的 Guava 库的前世今生。 本章节涉及到很多前几个章节中阐述的知识点。我们希望你是按照顺序阅读下来的&#xff0c;不然有些知识会一头雾水。 J…

Redis基础篇——Redis安装以及配置文件的修改

文章目录1. 认识Redis1.1 特征1.2 安装 Redis1. 安装 Redis 依赖2. 上传安装包1.3 默认启动1.4 指定配置启动1.5 开机自启&#xff08;推荐&#xff09;1. 认识Redis Redis 诞生于 2009 年&#xff0c;全称是 Remote Dictionary Server&#xff0c;远程词典服务器&#xff0c;…

Databend 开源周报 #73

Databend 是一款强大的云数仓。专为弹性和高效设计&#xff0c;自由且开源。 即刻体验云服务&#xff1a;https://app.databend.com。 What’s New 探索 Databend 本周新进展&#xff0c;遇到更贴近你心意的 Databend 。 Features & Improvements Multiple Catalogs …

hudi实战-- 核心点解析

目录 Hudi 基础功能 Hudi 简介 Hudi 功能 Hudi 的特性 Hudi 的 架构 Hudi 数据管理 Hudi 表数据结构 hoodie 文件 数据文件 数据存储概述 Metadata 元数据 Index 索引 索引策略 Data 数据 Hudi 核心点解析 基本概念 时间轴Timeline 文件管理 索引 Index 表的存储…

NiN详解

入门小菜鸟&#xff0c;希望像做笔记记录自己学的东西&#xff0c;也希望能帮助到同样入门的人&#xff0c;更希望大佬们帮忙纠错啦~侵权立删。 ✨完整代码在我的github上&#xff0c;有需要的朋友可以康康✨ https://github.com/tt-s-t/Deep-Learning.git 目录 一、NiN网络的…

【C语言开源库】 一个只有500行代码的开源http服务器:Tinyhttpd学习

项目搬运&#xff0c;带中文翻译&#xff1a;https://github.com/nengm/Tinyhttpd在嵌入式中&#xff0c;我们HTTP服务器用得最多的就是boa还有就是goahead,但是这2个代码量比较大&#xff0c;而Tinyhttpd只有几百行&#xff0c;比较有助于我们学习。一、编译及运行直接make之后…

用Python让奇怪的想法变成现实,2023年继续创作

2023年继续写作&#xff0c;用文章记录生活 时间过得真快&#xff0c;一下就到2023年了。 由于疫情肆虐&#xff0c;在网络的游弋的实现也长了&#xff0c;写作的自然也多了。 回想一下&#xff0c;2018-2021年这三年时间里一篇文章也没写过为0&#xff0c;哈哈&#xff0c;没…

【EHub_tx1_tx2_E100】Ubuntu18.04 + ROS_ Melodic + NVISTAR VP300 激光雷达 评测

简介&#xff1a;介绍NVISTAR 的二维DTOF激光雷达 在EHub_tx1_tx2_E100载板&#xff0c;TX1核心模块环境&#xff08;Ubuntu18.04&#xff09;下测试ROS驱动&#xff0c;打开使用RVIZ 查看点云数据&#xff0c;本文的前提条件是你的TX1里已经安装了ROS版本&#xff1a;Melodic。…

滴滴前端一面经典手写面试题

实现bind 实现bind要做什么 返回一个函数&#xff0c;绑定this&#xff0c;传递预置参数bind返回的函数可以作为构造函数使用。故作为构造函数时应使得this失效&#xff0c;但是传入的参数依然有效 // mdn的实现 if (!Function.prototype.bind) {Function.prototype.bind f…

Kuberneters(2)- Pod详解

第四章 实战入门 本章节将介绍如何在kubernetes集群中部署一个nginx服务&#xff0c;并且能够对其进行访问。 Namespace ​ Namespace是kubernetes系统中的一种非常重要资源&#xff0c;它的主要作用是用来实现多套环境的资源隔离或者多租户的资源隔离。 ​ 默认情况下&…

路由跳转同一个界面,但是params不同。页面不刷新?(路由的key)

文章目录引入知识点&#xff1a;路由的key值思路&#xff1a;结论&#xff1a;解决方法&#xff1a;效果&#xff1a;应用场景:引入知识点&#xff1a;路由的key值 如果不设置路由的key值&#xff0c;默认情况下是根据路径判断的&#xff0c;就是不包括params值 例子&#xff…

MySQL5-数据类型

目录 1.数值类型&#xff08;分为整型和浮点型&#xff09; 2.字符串类型 3.日期类型 MySQL和Java编程一样&#xff0c;创建表时要考虑数据类型。 MySQL表组成&#xff1a;列名/列数据类型&#xff1b;数据。 1.数值类型&#xff08;分为整型和浮点型&#xff09; 数据类型…

天工开物 #4 构建一个受保护的网站

前段时间&#xff0c;我出于兴趣试着做了一个需要登录鉴权才能访问的个人网站&#xff0c;最终以 Docusaurus[1] 为内容框架&#xff0c;Next.js[2] 做中间件&#xff0c;Vercel[3] 托管网站&#xff0c;再加上 Auth0[4] 作为鉴权解决方案&#xff0c;实现了一个基本免费的方案…

数位DP入门笔记(1)HUD-2089

题目&#xff1a; 题目理解和思路&#xff1a; 1.此题是给一个6位车牌号&#xff0c;正着不能含有连着的62&#xff0c;不能有4。 2.判断车牌号可能会采用dfs&#xff0c;因为每增加一位数就包含带4&#xff0c;或者形成62两种不合法情况&#xff08;事实上没有用到&#xf…