黑马 小兔鲜儿 uniapp 小程序开发- 推荐模块- day03

news2024/11/26 4:54:21

黑马 小兔鲜儿 uniapp 小程序开发- 02首页模块_软工菜鸡的博客-CSDN博客

小兔鲜儿 - 推荐模块- day03

主要实现 Tabs 交互、多 Tabs 列表分页加载数据。

动态获取数据

参考效果

推荐模块的布局结构是相同的,因此我们可以复用相同的页面及交互,只是所展示的数据不同。

静态结构

新建热门推荐页面文件,并在 pages.json 中添加路由(VS Code 插件自动完成)。

// /src/pages/hot/hot.vue
<script setup lang="ts">
// 热门推荐页 标题和url
const hotMap = [
  { type: '1', title: '特惠推荐', url: '/hot/preference' },
  { type: '2', title: '爆款推荐', url: '/hot/inVogue' },
  { type: '3', title: '一站买全', url: '/hot/oneStop' },
  { type: '4', title: '新鲜好物', url: '/hot/new' },
]
</script>

<template>
  <view class="viewport">
    <!-- 推荐封面图 -->
    <view class="cover">
      <image
        src="http://yjy-xiaotuxian-dev.oss-cn-beijing.aliyuncs.com/picture/2021-05-20/84abb5b1-8344-49ae-afc1-9cb932f3d593.jpg"
      ></image>
    </view>
    <!-- 推荐选项 -->
    <view class="tabs">
      <text class="text active">抢先尝鲜</text>
      <text class="text">新品预告</text>
    </view>
    <!-- 推荐列表 -->
    <scroll-view scroll-y class="scroll-view">
      <view class="goods">
        <navigator
          hover-class="none"
          class="navigator"
          v-for="goods in 10"
          :key="goods"
          :url="`/pages/goods/goods?id=`"
        >
          <image
            class="thumb"
            src="https://yanxuan-item.nosdn.127.net/5e7864647286c7447eeee7f0025f8c11.png"
          ></image>
          <view class="name ellipsis">不含酒精,使用安心爽肤清洁湿巾</view>
          <view class="price">
            <text class="symbol">¥</text>
            <text class="number">29.90</text>
          </view>
        </navigator>
      </view>
      <view class="loading-text">正在加载...</view>
    </scroll-view>
  </view>
</template>

<style lang="scss">
page {
  height: 100%;
  background-color: #f4f4f4;
}
.viewport {
  display: flex;
  flex-direction: column;
  height: 100%;
  padding: 180rpx 0 0;
  position: relative;
}
.cover {
  width: 750rpx;
  height: 225rpx;
  border-radius: 0 0 40rpx 40rpx;
  overflow: hidden;
  position: absolute;
  left: 0;
  top: 0;
}
.scroll-view {
  flex: 1;
}
.tabs {
  display: flex;
  justify-content: space-evenly;
  height: 100rpx;
  line-height: 90rpx;
  margin: 0 20rpx;
  font-size: 28rpx;
  border-radius: 10rpx;
  box-shadow: 0 4rpx 5rpx rgba(200, 200, 200, 0.3);
  color: #333;
  background-color: #fff;
  position: relative;
  z-index: 9;
  .text {
    margin: 0 20rpx;
    position: relative;
  }
  .active {
    &::after {
      content: '';
      width: 40rpx;
      height: 4rpx;
      transform: translate(-50%);
      background-color: #27ba9b;
      position: absolute;
      left: 50%;
      bottom: 24rpx;
    }
  }
}
.goods {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  padding: 0 20rpx 20rpx;
  .navigator {
    width: 345rpx;
    padding: 20rpx;
    margin-top: 20rpx;
    border-radius: 10rpx;
    background-color: #fff;
  }
  .thumb {
    width: 305rpx;
    height: 305rpx;
  }
  .name {
    height: 88rpx;
    font-size: 26rpx;
  }
  .price {
    line-height: 1;
    color: #cf4444;
    font-size: 30rpx;
  }
  .symbol {
    font-size: 70%;
  }
  .decimal {
    font-size: 70%;
  }
}

.loading-text {
  text-align: center;
  font-size: 28rpx;
  color: #666;
  padding: 20rpx 0 50rpx;
}
</style>

获取页面参数

热门推荐页要根据页面参数区分需要获取的是哪种类型的推荐列表,然后再去调用相应的接口,来获取不同的数据,再渲染到页面当中。

项目首页(传递参数)

// src/pages/index/components/HotPanel.vue
<navigator :url="`/pages/hot/hot?type=${item.type}`">
  …省略  
</navigator>

热门推荐页(获取参数)

// src/pages/hot/hot.vue
<script setup lang="ts">
// 热门推荐页 标题和url
const hotMap = [
  { type: '1', title: '特惠推荐', url: '/hot/preference' },
  { type: '2', title: '爆款推荐', url: '/hot/inVogue' },
  { type: '3', title: '一站买全', url: '/hot/oneStop' },
  { type: '4', title: '新鲜好物', url: '/hot/new' },
]
// uniapp 获取页面参数
const query = defineProps<{
  type: string
}>()
// console.log(query)
const currHot = hotMap.find((v) => v.type === query.type)
// 动态设置标题
uni.setNavigationBarTitle({ title: currHot!.title })
</script>

传递不同的页面参数,动态设置推荐页标题。

获取数据

地址参数

不同类型的推荐,需要调用不同的 API 接口:

type

推荐类型

接口路径

1

特惠推荐

/hot/preference

2

爆款推荐

/hot/inVogue

3

一站买全

/hot/oneStop

4

新鲜好物

/hot/new

接口调用

调用接口获取推荐商品列表的数据,然后再将这些数据渲染出来。

接口地址:见上表

请求方式:GET

请求参数:

Query:

字段名称

是否必须

默认值

备注

subType

推荐列表 Tab 项的 id

page

1

页码

pageSize

10

每页商品数量

请求封装

经过分析,尽管不同类型推荐的请求 url 不同,但请求参数及响应格式都具有一致性,因此可以将接口的调用进行封装,参考代码如下所示:

import { http } from '@/utils/http'
import type { PageParams } from '@/types/global'

type HotParams = PageParams & {
  /** Tab 项的 id,默认查询全部 Tab 项的第 1 页数据 */
  subType?: string
}
/**
 * 通用热门推荐类型
 * @param url 请求地址
 * @param data 请求参数
 */
export const getHotRecommendAPI = (url: string, data?: HotParams) => {
  return http<HotResult>({
    method: 'GET',
    url,
    data,
  })
}

类型声明

电商项目较为常见商品展示,商品的类型是可复用的,封装到 src/types/global.d.ts 文件中:

// src/types/global.d.ts
/** 通用商品类型 */
export type GoodsItem = {
  /** 商品描述 */
  desc: string
  /** 商品折扣 */
  discount: number
  /** id */
  id: string
  /** 商品名称 */
  name: string
  /** 商品已下单数量 */
  orderNum: number
  /** 商品图片 */
  picture: string
  /** 商品价格 */
  price: number
}

其实猜你喜欢的商品类型也相同,可复用通用商品类型,封装到 src/services/home.ts 文件中:

// src/services/home.ts
import type { GoodsItem } from '@/types/global'

// GuessItem 和 GoodsItem 类型相同
export type GuessItem = GoodsItem

热门推荐类型如下,新建 src/types/hot.d.ts 文件:

import type { PageResult, GoodsItem } from './global'

/** 热门推荐 */
export type HotResult = {
  /** id信息 */
  id: string
  /** 活动图片 */
  bannerPicture: string
  /** 活动标题 */
  title: string
  /** 子类选项 */
  subTypes: SubTypeItem[]
}

/** 热门推荐-子类选项 */
export type SubTypeItem = {
  /** 子类id */
  id: string
  /** 子类标题 */
  title: string
  /** 子类对应的商品集合 */
  goodsItems: PageResult<GoodsItem>
}

最后,把获取到的数据结合模板语法渲染到页面中。

多 Tabs 分页加载

需要根据当前用户选中的 Tabs 加载对应的列表数据。

Tabs 交互基础

当用户点击页面中的 Tab 后,切换展示相应的商品列表,功能相对简单,快速实现即可。

参考代码

<script setup lang="ts">
// 高亮的下标
const activeIndex = ref(0)
</script>

<template>
  <!-- 推荐选项 -->
  <view class="tabs">
    <text
      class="text"
      v-for="(item, index) in subTypes"
      :key="item.id"
      :class="{ active: index === activeIndex }"
      @tap="activeIndex = index"
    >
      {{ item.title }}
    </text>
  </view>
  <!-- 推荐列表 -->
  <scroll-view
    scroll-y
    class="scroll-view"
    v-for="(item, index) in subTypes"
    :key="item.id"
    v-show="activeIndex === index"
  >
    ...省略
  </scroll-view>
</template>

加载选中 Tabs 分页数据

根据当前用户选中的 Tabs 加载对应的列表数据。

操作流程

  1. 根据高亮下标,获取对应列表数据
  2. 提取列表的分页参数,用于发送请求
  3. 滚动触底事件,页码累加,数组追加,退出判断等业务和常规分页基本一致

参考代码(总)

热门推荐页

<script setup lang="ts">
import { getHotRecommendAPI } from '@/services/hot'
import type { SubTypeItem } from '@/types/hot'
import { onLoad } from '@dcloudio/uni-app'
import { ref } from 'vue'

// 热门推荐页 标题和url
const hotMap = [
  { type: '1', title: '特惠推荐', url: '/hot/preference' },
  { type: '2', title: '爆款推荐', url: '/hot/inVogue' },
  { type: '3', title: '一站买全', url: '/hot/oneStop' },
  { type: '4', title: '新鲜好物', url: '/hot/new' },
]

// uniapp 获取页面参数
const query = defineProps<{
  type: string
}>()
// 获取当前推荐信息
const currHot = hotMap.find((v) => v.type === query.type)
// 动态设置标题
uni.setNavigationBarTitle({ title: currHot!.title })

// 推荐封面图
const bannerPicture = ref('')
// 推荐选项
const subTypes = ref<(SubTypeItem & { finish?: boolean })[]>([])
// 高亮的下标
const activeIndex = ref(0)
// 获取热门推荐数据
const getHotRecommendData = async () => {
  const res = await getHotRecommendAPI(currHot!.url, {
    // 技巧:环境变量,开发环境,修改初始页面方便测试分页结束
    page: import.meta.env.DEV ? 30 : 1,
    pageSize: 10,
  })
  // 保存封面
  bannerPicture.value = res.result.bannerPicture
  // 保存列表
  subTypes.value = res.result.subTypes
}

// 页面加载
onLoad(() => {
  getHotRecommendData()
})

// 滚动触底
const onScrolltolower = async () => {
  // 获取当前选项
  const currsubTypes = subTypes.value[activeIndex.value]
  // 分页条件
  if (currsubTypes.goodsItems.page < currsubTypes.goodsItems.pages) {
    // 当前页码累加
    currsubTypes.goodsItems.page++
  } else {
    // 标记已结束
    currsubTypes.finish = true
    // 退出并轻提示
    return uni.showToast({ icon: 'none', title: '没有更多数据了~' })
  }

  // 调用API传参
  const res = await getHotRecommendAPI(currHot!.url, {
    subType: currsubTypes.id,
    page: currsubTypes.goodsItems.page,
    pageSize: currsubTypes.goodsItems.pageSize,
  })
  // 新的列表选项
  const newsubTypes = res.result.subTypes[activeIndex.value]
  // 数组追加
  currsubTypes.goodsItems.items.push(...newsubTypes.goodsItems.items)
}
</script>

<template>
  <view class="viewport">
    <!-- 推荐封面图 -->
    <view class="cover">
      <image :src="bannerPicture"></image>
    </view>
    <!-- 推荐选项 -->
    <view class="tabs">
      <text
        v-for="(item, index) in subTypes"
        :key="item.id"
        class="text"
        :class="{ active: index === activeIndex }"
        @tap="activeIndex = index"
        >{{ item.title }}</text
      >
    </view>
    <!-- 推荐列表 -->
    <scroll-view
      v-for="(item, index) in subTypes"
      :key="item.id"
      v-show="activeIndex === index"
      scroll-y
      class="scroll-view"
      @scrolltolower="onScrolltolower"
    >
      <view class="goods">
        <navigator
          hover-class="none"
          class="navigator"
          v-for="goods in item.goodsItems.items"
          :key="goods.id"
          :url="`/pages/goods/goods?id=${goods.id}`"
        >
          <image class="thumb" :src="goods.picture"></image>
          <view class="name ellipsis">{{ goods.name }}</view>
          <view class="price">
            <text class="symbol">¥</text>
            <text class="number">{{ goods.price }}</text>
          </view>
        </navigator>
      </view>
      <view class="loading-text">
        {{ item.finish ? '没有更多数据了~' : '正在加载...' }}
      </view>
    </scroll-view>
  </view>
</template>

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

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

相关文章

轻松打造自己的ChatGPT应用,AI应用,源码附赠

这里写自定义目录标题 前言简介 前言 大家好&#xff0c;我是静幽水&#xff0c;目前是一名大厂全栈工程师&#xff0c;练习时长两年&#xff0c;擅长Java后端&#xff0c;Vue前端&#xff0c;小程序编程&#xff0c;Python编程&#xff0c;ChatGPT 提示词等技术。现在正在系统…

建筑模板木模好还是钢模好

在建筑施工中&#xff0c;模板是一项关键的工程&#xff0c;对于建筑结构的质量和施工效率起着重要作用。在选择模板材料时&#xff0c;木模和钢模都是常见的选择。本文将比较木模和钢模的优缺点&#xff0c;以帮助您做出明智的选择。 正文&#xff1a;一、木模&#xff1a;传统…

信创国产化解决方案

近年来&#xff0c;随着信息技术的飞速发展&#xff0c;信创产业成为国家发展的重要战略之一。2018年以来我国将信创纳入国家战略&#xff0c;提出了“28”发展体系&#xff0c;随后扩展至更多行业&#xff0c;演变为“28N”应用体系。2023年中国信创产业逐步走向应用落地阶段。…

sql函数实现模糊精确匹配

sql函数实现模糊精确匹配 例如&#xff1a; 查询的时候匹配[‘1’] 就只匹配1的 &#xff0c;而不是15的也会模糊查询进去 slq函数如下&#xff1a; CREATE OR REPLACE FUNCTION does_string_array_intersect ( target_string TEXT, input_strings TEXT [] ) RETURNS BOOLEA…

单元格法求解多边形最大内接矩形问题【思路讲解+java实现】

问题描述 给定一个多边形的点集&#xff0c;希望找出多边形内部面积最大的矩形。该问题可能出现在&#xff0c;从一个多边形废料上面切割出一个最大的矩形&#xff0c;该矩形可以重复利用&#xff0c;解决该问题可以节约原材料&#xff0c;降低企业运作成本 问题解决方案 本…

解决Selenium元素拖拽不生效Bug

前几天在使用Selenium进行元素拖拽操作时&#xff0c;发现Selenium自带的元素拖拽方法&#xff08;dragAndDrop()&#xff09;不生效&#xff0c;网上的回答也是五花八门&#xff0c;比较混乱&#xff0c;尝试了以下几种方法均无法解决。 方案1&#xff1a;通过dragAndDrop()方…

群晖NAS如何在内网部署HTTPS服务让浏览器信任证书

前言 最近在折腾内部部署Web服务。通过Vue实现一个H5的内部的管理服务。但在实际部署过程中由于种种原因&#xff0c;必须部署成Https服务。但在部署成Https服务后&#xff0c;由于没有HTTPS证书&#xff0c;每次进入页面都会被浏览器拦截。使用起来非常不便。于是开始各种Goo…

显示器显示的画面突然偏红色如何解决

显示器显示的画面突然偏红色如何解决 1. 概述2. 解决方法结束语 1. 概述 显示器显示的画面突然偏红色 &#xff0c;使用向日葵远程电脑&#xff0c;看到的画面是正常的&#xff0c;但是显示器上的画面确还是骗红的&#xff0c;这时候就需要看一下是不是开启了系统也夜间模式&a…

Linux之使用LAMP搭建私有云存储

目录 Linux之使用LAMP搭建私有云存储 恢复快照&#xff0c;关闭安全软件 搭建LAMP环境 下载安装依赖包 下载nextcloud软件 解压nextcloud 设置nextcloud安装命令权限 数据库配置 设置数据库 重启数据库 配置httpd 重启httpd服务 安装 打开浏览器后输入服务器IP地址…

LeetCode(力扣)1005. K 次取反后最大化的数组和Python

LeetCode1005. K 次取反后最大化的数组和 题目链接代码 题目链接 https://leetcode.cn/problems/maximize-sum-of-array-after-k-negations/ 代码 class Solution:def largestSumAfterKNegations(self, nums: List[int], k: int) -> int:nums.sort(keylambda x: abs(x),…

一款攻击面管理必备工具-Goby

引言 在正式介绍Goby之前,我们先简单介绍下网络功防的基本常识: 首先,对于攻击方,我们需要了解一个常见的攻击过程: 攻击者需要明确探测目标,锁定目标的地理位置、IP、域名等基本信息;对目标ip、域名进行存活性判定,对其操作系统、开放端口、服务等信息进行识别;针对…

【1462. 课程表 IV】

来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 描述&#xff1a; 你总共需要上 numCourses 门课&#xff0c;课程编号依次为 0 到 numCourses-1 。你会得到一个数组 prerequisite &#xff0c;其中 prerequisites[i] [ai, bi] 表示如果你想选 bi 课程&#xff0c;你…

你真的会报bug吗?常见10条错误

几乎每一位测试员&#xff0c;都会因为自己发现了一个bug而沾沾自喜&#xff0c;然后迫不及待地报bug。此时&#xff0c;恨不得有个喇叭&#xff0c;在整个办公室广而告之一下&#xff0c;实际上这样的行为并不可取&#xff0c;因为软件开发人员最怕的就是思路被打断&#xff0…

关于vue封装form表单单向流数据问题

vue在封装form表单业务组件问题时&#xff0c;传参的方式可能是 组件接收的形式这样很容易打破vue 的单向流数据规则&#xff0c;这样写肯定不会影响功能&#xff0c;只不过代码离屎山越来越近。 创建一个计算属性&#xff0c;get获取form 再利用 proxy 代理去代理这个对象&am…

DBC文件解析

一.candb 二.DBC文件解析 NS_ : NS_DESC_&#xff1a;用于描述网络信号的描述信息。 CM_&#xff1a;用于定义信号的描述信息。 BA_DEF_&#xff1a;定义信号的属性。 BA_&#xff1a;为信号属性定义值。 VAL_&#xff1a;为信号的枚举值定义标签。 CAT_DEF_&#xff1a;定义…

SoftwareTest2 - 软件测试相关概念

软件测试答疑篇 目标一 . 什么是需求二 . 测试用例三 . 什么是 BUG四 . 开发模型4.1 软件的生命周期需求分析计划设计编码测试运行维护 4.2 软件测试的生命周期需求分析测试计划测试设计与开发执行测试测试评估 4.3 常见模型瀑布模型螺旋模型增量模型、迭代模型敏捷模型scrum模…

GO语言篇之embed

GO语言篇之embed 文章目录 GO语言篇之embed前言目录结构文件转[]byte文件转string多文件转embed.FS目录转embed.FS文件和目录组合的方式转embed.FS 前言 embed是Go语言提供的一种机制&#xff0c;可使静态文件或文件夹嵌入Go语言程序中&#xff0c;使我们Go语言的可执行文件包…

kibana报错内存溢出问题解决

一、背景&#xff1a; kibana内存溢出&#xff0c;进程被kill掉&#xff0c;导致前端页面访问不到。 报错内容 二、报错原因&#xff1a; 发现是前端 js 报的内存 oom 异常&#xff0c;通过网上资料发现node.js 的默认内存大小为1.4G Node 中通过 JavaScript 使用内存时只能…

PCL入门(六):深度图提取边界

目录 1. 深度图介绍2. 深度图生成3. 边界提取 1. 深度图介绍 参考《02-深度图》 深度图像&#xff08;Depth Images&#xff09;也被称为距离影像&#xff08;Range Image&#xff09;&#xff0c;是指将从图像采集器到场景中各点的距离值作为像素值的图像&#xff0c;它直接…

CentOS7上从0开始搭建Zookeeper集群

CentOS7上搭建Zookeeper集群 环境准备安装jdk安装zookeeper下载zookeeper解压zookeeper修改zookeeper配置文件 搭建zookeeper集群修改zoo.cfg文件添加myid文件启动zookeeper集群 环境准备 首先你需要准备三台zookeeper&#xff08;待会会讲zookeeper的安装流程&#xff09;&am…