uniapp 小兔鲜儿 - 首页模块(2)

news2024/9/29 7:25:59

目录

热门推荐

首页 – 热门推荐组件 

首页 – 获取热门推荐数据

首页 – 热门推荐数据类型并渲染

猜你喜欢

首页 – 猜你喜欢组件

首页 – 获取猜你喜欢数据

首页 – 猜你喜欢数据类型和渲染

首页 – 猜你喜欢分页准备

首页 – 猜你喜欢分页加载

 首页 – 猜你喜欢分页条件

首页 – 下拉刷新

首页触发下拉刷新

猜你喜欢组件定义重置数据的方法

骨架屏


热门推荐

热门推荐功能,后端根据用户的消费习惯等信息向用户推荐的一系列商品,前端负责展示这些商品展示给用户。

参考效果

热门推荐

首页 – 热门推荐组件 

 1. 准备组件(只有首页使用)

热门推荐布局为独立的组件 HotPanel,属于首页的业务组件,存放到首页的 components 目录中。

<script setup lang="ts">
//
</script>

<template>
  <!-- 推荐专区 -->
  <view class="panel hot">
    <view class="item" v-for="item in 4" :key="item">
      <view class="title">
        <text class="title-text">特惠推荐</text>
        <text class="title-desc">精选全攻略</text>
      </view>
      <navigator hover-class="none" url="/pages/hot/hot" class="cards">
        <image
          class="image"
          mode="aspectFit"
          src="https://pcapi-xiaotuxian-front-devtest.itheima.net/miniapp/uploads/goods_small_1.jpg"
        ></image>
        <image
          class="image"
          mode="aspectFit"
          src="https://pcapi-xiaotuxian-front-devtest.itheima.net/miniapp/uploads/goods_small_2.jpg"
        ></image>
      </navigator>
    </view>
  </view>
</template>

<style lang="scss">
/* 热门推荐 */
.hot {
  display: flex;
  flex-wrap: wrap;
  min-height: 508rpx;
  margin: 20rpx 20rpx 0;
  border-radius: 10rpx;
  background-color: #fff;

  .title {
    display: flex;
    align-items: center;
    padding: 24rpx 24rpx 0;
    font-size: 32rpx;
    color: #262626;
    position: relative;
    .title-desc {
      font-size: 24rpx;
      color: #7f7f7f;
      margin-left: 18rpx;
    }
  }

  .item {
    display: flex;
    flex-direction: column;
    width: 50%;
    height: 254rpx;
    border-right: 1rpx solid #eee;
    border-top: 1rpx solid #eee;
    .title {
      justify-content: start;
    }
    &:nth-child(2n) {
      border-right: 0 none;
    }
    &:nth-child(-n + 2) {
      border-top: 0 none;
    }
    .image {
      width: 150rpx;
      height: 150rpx;
    }
  }
  .cards {
    flex: 1;
    padding: 15rpx 20rpx;
    display: flex;
    justify-content: space-between;
    align-items: center;
  }
}
</style>


2. 导入并使用组件

import HotPanel from "./componets/HotPanel.vue";  
<HotPanel></HotPanel>

首页 – 获取热门推荐数据

1. 封装获取热门推荐数据API

export const getHomeHotAPI = () => {
  return http<HotItem[]>({
    method: 'GET',
    url: '/home/hot/mutli',
  })
}


2. 页面初始化调用API

import { onLoad } from "@dcloudio/uni-app";
import { getHomeHotAPI } from "@/services/home";
import type { HotItem } from "@/types/home";
import { ref } from "vue";
const getHomeHotData = async () => {
  const res = await getHomeHotAPI();
  hotList.value = res.result;
};
onLoad(() => {
  getHomeHotData();
});

首页 – 热门推荐数据类型并渲染

1. 定义热门推荐数据类型

/** 首页-热门推荐数据类型 */
export type HotItem = {
  /** 说明 */
  alt: string
  /** id */
  id: string
  /** 图片集合[ 图片路径 ] */
  pictures: string[]
  /** 跳转地址 */
  target: string
  /** 标题 */
  title: string
  /** 推荐类型 */
  type: string
}


2. 指定类型并传值给子组件

const hotList = ref<HotItem[]>([])
<HotPanel :list="hotList" />
import type { HotItem } from "@/types/home";
defineProps<{
  list: HotItem[];
}>();


3. 渲染热门推荐数据

  <!-- 推荐专区 -->
  <view class="panel hot">
    <view class="item" v-for="item in list" :key="item.id">
      <view class="title">
        <text class="title-text">{{ item.title }}</text>
        <text class="title-desc">{{ item.alt }}</text>
      </view>
      <navigator hover-class="none" url="/pages/recommend/recommend" class="cards">
        <image v-for="src in item.pictures" :key="src" :src="src"></image>
      </navigator>
    </view>
  </view>

猜你喜欢

参考效果

猜你喜欢功能,后端根据用户的浏览记录等信息向用户随机推荐的一系列商品,前端负责把商品在多个页面中展示

首页 – 猜你喜欢组件

1. 准备组件(通用组件)

猜你喜欢是一个通用组件 XtxGuess,多个页面会用到该组件,存放到 src/components 目录中。

<script setup lang="ts">
//
</script>

<template>
  <!-- 猜你喜欢 -->
  <view class="caption">
    <text class="text">猜你喜欢</text>
  </view>
  <view class="guess">
    <navigator
      class="guess-item"
      v-for="item in 10"
      :key="item"
      :url="`/pages/goods/goods?id=4007498`"
    >
      <image
        class="image"
        mode="aspectFill"
        src="https://pcapi-xiaotuxian-front-devtest.itheima.net/miniapp/uploads/goods_big_1.jpg"
      ></image>
      <view class="name"> 德国THORE男表 超薄手表男士休闲简约夜光石英防水直径40毫米 </view>
      <view class="price">
        <text class="small">¥</text>
        <text>899.00</text>
      </view>
    </navigator>
  </view>
  <view class="loading-text"> 正在加载... </view>
</template>

<style lang="scss">
:host {
  display: block;
}
/* 分类标题 */
.caption {
  display: flex;
  justify-content: center;
  line-height: 1;
  padding: 36rpx 0 40rpx;
  font-size: 32rpx;
  color: #262626;
  .text {
    display: flex;
    justify-content: center;
    align-items: center;
    padding: 0 28rpx 0 30rpx;

    &::before,
    &::after {
      content: '';
      width: 20rpx;
      height: 20rpx;
      background-image: url(@/static/images/bubble.png);
      background-size: contain;
      margin: 0 10rpx;
    }
  }
}

/* 猜你喜欢 */
.guess {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  padding: 0 20rpx;
  .guess-item {
    width: 345rpx;
    padding: 24rpx 20rpx 20rpx;
    margin-bottom: 20rpx;
    border-radius: 10rpx;
    overflow: hidden;
    background-color: #fff;
  }
  .image {
    width: 304rpx;
    height: 304rpx;
  }
  .name {
    height: 75rpx;
    margin: 10rpx 0;
    font-size: 26rpx;
    color: #262626;
    overflow: hidden;
    text-overflow: ellipsis;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
  }
  .price {
    line-height: 1;
    padding-top: 4rpx;
    color: #cf4444;
    font-size: 26rpx;
  }
  .small {
    font-size: 80%;
  }
}
// 加载提示文字
.loading-text {
  text-align: center;
  font-size: 28rpx;
  color: #666;
  padding: 20rpx 0;
}
</style>


2. 定义组件类型、

// types/components.d.ts
import XtxGuess from '@/components/XtxGuess.vue'
declare module '@vue/runtime-core' {
  export interface GlobalComponents {
    XtxGuess: typeof XtxGuess
  }
}


3. 准备 scroll-view 滚动容器

  <scroll-view scroll-y class="scroll">
    <XtxSwiper :list="bannerList" />
    <CategoryPanel :list="categoryList" />
    <HotPanel :list="hotList"></HotPanel>
    <XtxGuess></XtxGuess>
    <view class="index"> </view
  ></scroll-view>


4. 设置 page 和 scroll-view 样式

<style lang="scss">
page {
  background-color: #f7f7f7;
  height: 100%;
  display: flex;
  flex-direction: column;
}
.scroll {
  flex: 1;
}
</style>

首页 – 获取猜你喜欢数据

1. 封装获取猜你喜欢数据API、

/**
 * 猜你喜欢-小程序
 */
export const getHomeGoodsGuessLikeAPI = (data?: PageParams) => {
  return http<PageResult<GuessItem>>({
    method: 'GET',
    url: '/home/goods/guessLike',
    data,
  })
}


2. 组件挂载完毕调用API

// 获取猜你喜欢列表数据
const getHomeGoodsGuessLikeData = async () => {
const res = await getHomeGoodsGuessLikeAPI()
console.log(res)
}
// 组件挂载完毕
onMounted(() => {
getHomeGoodsGuessLikeData()
})

首页 – 猜你喜欢数据类型和渲染

/** 通用分页结果类型 */
export type PageResult<T> = {
  /** 列表数据 */
  items: T[]
  /** 总条数 */
  counts: number
  /** 当前页数 */
  page: number
  /** 总页数 */
  pages: number
  /** 每页条数 */
  pageSize: number
}
/** 猜你喜欢-商品类型 */
export type GuessItem = {
  /** 商品描述 */
  desc: string
  /** 商品折扣 */
  discount: number
  /** id */
  id: string
  /** 商品名称 */
  name: string
  /** 商品已下单数量 */
  orderNum: number
  /** 商品图片 */
  picture: string
  /** 商品价格 */
  price: number
}
/** 通用分页参数类型 */
export type PageParams = {
  /** 页码:默认值为 1 */
  page?: number
  /** 页大小:默认值为 10 */
  pageSize?: number
}
export const getHomeGoodsGuessLikeAPI = (data?: PageParams) => {
  return http<PageResult<GuessItem>>({
    method: 'GET',
    url: '/home/goods/guessLike',
    data,
  })
}

 

const guessList = ref<GuessItem[]>([])
const getHomeGoodsGuessLikeData = async () => {
    const res = await getHomeGoodsGuessLikeAPI()
    guessList.value = res.result.items
}

  <view class="guess">
    <navigator class="guess-item" v-for="item in guessList" :key="item.id">
      <image class="image" mode="aspectFill" :src="item.picture"></image>
      <view class="name">{{ item.name }}</view>
      <view class="price">
        <text class="small">¥</text>
        <text>{{ item.price }}</text>
      </view>
    </navigator>
  </view>

首页 – 猜你喜欢分页准备

 滚动触底 和 模板ref

// pages/index/index.vue
<script setup lang="ts">
import type { XtxGuessInstance } from '@/types/components'
import { ref } from 'vue'
// 获取猜你喜欢组件实例
const guessRef = ref<XtxGuessInstance>()

// 滚动触底事件
const onScrolltolower = () => {
  guessRef.value?.getMore()
}
</script>

<template>
  <!-- 滚动容器 -->
  <scroll-view scroll-y @scrolltolower="onScrolltolower">
    <!-- 猜你喜欢 -->
    <XtxGuess ref="guessRef" />
  </scroll-view>
</template>

组件实例类型

// 组件实例类型
export type XtxGuessInstance = InstanceType<typeof XtxGuess>

暴露方法

// 暴露方法
defineExpose({
  getMore: getHomeGoodsGuessLikeData,
});

首页 – 猜你喜欢分页加载

/**
 * 猜你喜欢-小程序
 */
export const getHomeGoodsGuessLikeAPI = (data?: PageParams) => {
  return http<PageResult<GuessItem>>({
    method: 'GET',
    url: '/home/goods/guessLike',
    data,
  })
}
/** 通用分页参数类型 */
export type PageParams = {
  /** 页码:默认值为 1 */
  page?: number
  /** 页大小:默认值为 10 */
  pageSize?: number
}
// 分页参数
const pageParams: Required < PageParams > = {
	page: 1,
	pageSize: 10,
}
const getHomeGoodsGuessLikeData = async () => {
	const res = await getHomeGoodsGuessLikeAPI(pageParams)
	// 数组追加
	guessList.value.push(...res.result.items)
	// 页码累加
	pageParams.page++
}

 首页 – 猜你喜欢分页条件

// src/components/XtxGuess.vue
<script setup lang="ts">
import { getHomeGoodsGuessLikeAPI } from '@/services/home'
import type { PageParams } from '@/types/global'
import type { GuessItem } from '@/types/home'
import { onMounted, ref } from 'vue'

// 分页参数
const pageParams: Required<PageParams> = {
  page: 1,
  pageSize: 10,
}
// 猜你喜欢的列表
const guessList = ref<GuessItem[]>([])
// 已结束标记
const finish = ref(false)
// 获取猜你喜欢数据
const getHomeGoodsGuessLikeData = async () => {
  // 退出分页判断
  if (finish.value === true) {
    return uni.showToast({ icon: 'none', title: '没有更多数据~' })
  }
  const res = await getHomeGoodsGuessLikeAPI(pageParams)
  // 数组追加
  guessList.value.push(...res.result.items)
  // 分页条件
  if (pageParams.page < res.result.pages) {
    // 页码累加
    pageParams.page++
  } else {
    finish.value = true
  }
}
// 重置数据
const resetData = () => {
  pageParams.page = 1
  guessList.value = []
  finish.value = false
}
// 组件挂载完毕
onMounted(() => {
  getHomeGoodsGuessLikeData()
})
// 暴露方法
defineExpose({
  resetData,
  getMore: getHomeGoodsGuessLikeData,
})
</script>

<template>
  <!-- 猜你喜欢 -->
  <view class="caption">
    <text class="text">猜你喜欢</text>
  </view>
  <view class="guess">
    <navigator
      class="guess-item"
      v-for="item in guessList"
      :key="item.id"
      :url="`/pages/goods/goods`"
    >
      <image class="image" mode="aspectFill" :src="item.picture"></image>
      <view class="name"> {{ item.name }} </view>
      <view class="price">
        <text class="small">¥</text>
        <text>{{ item.price }}</text>
      </view>
    </navigator>
  </view>
  <view class="loading-text">
    {{ finish ? '没有更多数据~' : '正在加载...' }}
  </view>
</template>

首页 – 下拉刷新

首页触发下拉刷新

下拉刷新实际上是在用户操作下拉交互时重新调用接口,然后将新获取的数据再次渲染到页面中。

操作步骤

基于 scroll-view 组件实现下拉刷新,需要通过以下方式来实现下拉刷新的功能。

  • 配置 refresher-enabled 属性,开启下拉刷新交互
  • 监听 @refresherrefresh 事件,判断用户是否执行了下拉操作
  • 配置 refresher-triggered 属性,关闭下拉状态
// src/pages/index/index.vue
<script setup lang="ts">
// 下拉刷新状态
const isTriggered = ref(false)
// 自定义下拉刷新被触发
const onRefresherrefresh = async () => {
  // 开启动画
  isTriggered.value = true
  // 重置猜你喜欢组件数据
  guessRef.value?.resetData() // 加载数据
  await Promise.all([getHomeBannerData(), getHomeCategoryData(), getHomeHotData()]) // 关闭动画
  isTriggered.value = false
}
</script>

<!-- 滚动容器 -->
<scroll-view
  refresher-enabled
  @refresherrefresh="onRefresherrefresh"
  :refresher-triggered="isTriggered"
  class="scroll-view"
  scroll-y
>
  …省略
</scroll-view>

猜你喜欢组件定义重置数据的方法

// src/components/XtxGuess.vue
// 重置数据
const resetData = () => {
  pageParams.page = 1
  guessList.value = []
  finish.value = false
}
// 暴露方法
defineExpose({
  resetData,
})

骨架屏

骨架屏是页面的一个空白版本,通常会在页面完全渲染之前,通过一些灰色的区块大致勾勒出轮廓,待数据加载完成后,再替换成真实的内容。

参考效果

骨架屏作用是缓解用户等待时的焦虑情绪,属于用户体验优化方案。

 

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

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

相关文章

RabbitMQ启动服务报错1067解决方案

首先&#xff1a; 你的 Erlang正确下载安装&#xff0c;且配置完成环境变量&#xff0c;可在命令行键入erl&#xff0c;若显示erlang版本则说明环境变量配置成功。如下&#xff1a; 原因分析&#xff1a; 1. 电脑名称为中文 2. erlang和rabbitmq版本不匹配 3. 安装目录有空格…

211、仿真-基于51单片机土壤湿度智能盆栽灌溉报警Proteus仿真设计(程序+Proteus仿真+配套资料等)

毕设帮助、开题指导、技术解答(有偿)见文未 目录 一、硬件设计 二、设计功能 三、Proteus仿真图 四、程序源码 资料包括&#xff1a; 需要完整的资料可以点击下面的名片加下我&#xff0c;找我要资源压缩包的百度网盘下载地址及提取码。 方案选择 单片机的选择 方案一&am…

诚迈科技荣膺小米“最佳供应商奖”

近日&#xff0c;诚迈科技受邀参加小米战略合作伙伴HBR总结会。诚迈科技以尽职尽责的合作态度、精益求精的交付质量荣膺小米公司颁发的最佳供应商奖&#xff0c;其性能测试团队荣获优秀团队奖。 诚迈科技与小米在手机终端方向一直保持着密切的合作关系&#xff0c;涉及系统框架…

机械臂-五次多项式与三次多项式对比

##1、三次多项式算法 代码如下&#xff1a; L(1) Link( d, 0.081, a ,-0.01 , alpha, pi/2 ,offset,0); L(2) Link( d, 0 , a , 0.099 , alpha, 0 ,offset,pi/2); L(3) Link( d, 0 , a , -0.01 , alpha,pi/2,offset,pi/2); L(4) Link( d, 0.1170.123,…

JVM中分代回收机制

为什么要分为新生代和老年代&#xff1f; 分为新生代&#xff08;Young Generation&#xff09;和老年代&#xff08;Old Generation&#xff09;是为了更有效地管理和优化内存的使用。 新生代主要存放生命周期较短的对象&#xff0c;例如方法的局部变量、临时变量等。由于这…

奥威BI财务数据分析方案:借BI之利,成就智能财务分析

随着智能技术的发展&#xff0c;各行各业都走上借助智能技术高效运作道路&#xff0c;财务数据分析也不例外。借助BI商业智能技术能够让财务数据分析更高效、便捷、直观立体&#xff0c;也更有助于发挥财务数据分析作为企业经营管理健康晴雨表的作用。随着BI财务数据分析经验的…

数据结构介绍

1、什么是数据结构呢&#xff1f; 计算机底层存储、组织数据的方式。是指数据相互之间是以什么方式排列在一起的。数据结构是为了更方便的管理和使用数据&#xff0c;需要结合具体的业务来进行选择。一般情况下&#xff0c;精心选择的数据结构可以带来更高的运行或者存储效率。…

STM32单片机并口通信编程实例:代码详解与应用案例

引言&#xff1a; 单片机并口通信是一种传统而常用的通信方式&#xff0c;通过并行方式进行数据传输。尽管串口通信在现代应用中更加普遍&#xff0c;但并口通信在一些特定领域的应用仍然具有重要意义。本文将介绍单片机并口通信的原理、配置和实践方法&#xff0c;并给出STM32…

中电金信通过KCSP认证 云原生能力获权威认可

中电金信通过KCSP&#xff08;Kubernetes Certified Service Provider&#xff09;认证&#xff0c;正式成为CNCF&#xff08;云原生计算基金会&#xff09;官方认证的 Kubernetes 服务提供商。 Kubernetes是容器管理编排引擎&#xff0c;底层实现为容器技术&#xff0c;是云原…

【数据结构与算法】普里姆算法

普里姆算法 最小生成树 最小生成树&#xff0c;简称MST。 给定一个带权的无向连通图&#xff0c;如何选取一棵生成树&#xff0c;使树上所有边上权的总和为最小&#xff0c;这就叫最小生成树。N 个顶点&#xff0c;一定有 N - 1 条边半酣全部顶点N - 1 条边都在图中举例说明…

爬虫逆向实战(五)--猿人学第三题

一、数据接口分析 主页地址&#xff1a;猿人学第三题 1、抓包 通过抓包可以发现数据接口是api/match/3 2、判断是否有加密参数 请求参数是否加密&#xff1f; 无请求头是否加密&#xff1f; 无响应是否加密&#xff1f; 无cookie是否加密&#xff1f; 无 二、发送请求 …

【Java】智慧工地SaaS平台源码:AI/云计算/物联网/智慧监管

智慧工地是指运用信息化手段&#xff0c;围绕施工过程管理&#xff0c;建立互联协同、智能生产、科学管理的施工项目信息化生态圈&#xff0c;并将此数据在虚拟现实环境下与物联网采集到的工程信息进行数据挖掘分析&#xff0c;提供过程趋势预测及专家预案&#xff0c;实现工程…

Redis对象和五种常用数据类型

Redisobject 对象 对象分为键对象和值对象 键对象一般是string类型 值对象可以是string&#xff0c;list&#xff0c;set,zset,hash q&#xff1a;redisobj的结构 typedef struct redisObject { //类型 unsigned type:4; //编码 unsigned encoding:4; //指向底层实现…

ArcGIS Pro如何制作不规则形状图例

在默认的情况下&#xff0c;ArcGIS Pro生成的图例是标准的点、直线和矩形的&#xff0c;对于湖泊等要素而言&#xff0c;这样的表示方式不够直观&#xff0c;我们可以将其优化一下&#xff0c;制作不规则的线和面来代替原有图例&#xff0c;这里为大家介绍一下制作方法&#xf…

广东灯具3D扫描抄数建模服务3D测绘出图纸三维逆向设计-CASAIM

灯具三维逆向建模是一种将实际物体转换为数字模型的过程。通过逆向工程技术&#xff0c;可以将现有的灯具进行3D扫描&#xff0c;然后利用专业的逆向设计软件将其转换为准确的三维模型。 以下是CASAIM实施灯具三维逆向建模的一般步骤图&#xff1a; 1. 扫描&#xff1a;三维扫…

基于Prometheus监控Kubernetes集群

目录 一、环境准备 1.1、主机初始化配置 1.2、部署docker环境 二、部署kubernetes集群 2.1、组件介绍 2.2、配置阿里云yum源 2.3、安装kubelet kubeadm kubectl 2.4、配置init-config.yaml 2.5、安装master节点 2.6、安装node节点 2.7、安装flannel、cni 2.8、部署测…

读高性能MySQL(第4版)笔记03_监控

1. 服务级别帮助你定义客户满意的程度和标准&#xff0c;以便你在解决性能、可扩展性挑战等事情与开发内部工具之间做出时间权衡 2. 服务水平指标&#xff08;SLI&#xff09; 2.1. 如何衡量客户是否满意 3. 服务水平目标&#xff08;SLO&#xff09; 3.1. 为了确保客户满意…

三维模型OSGB格式轻量化顶点压缩主要技术方法分析

三维模型OSGB格式轻量化顶点压缩主要技术方法分析 在三维模型应用中&#xff0c;轻量化处理是提高数据传输效率、减少渲染时间和优化用户体验的重要手段。而OSGB格式是一种常见的三维模型格式&#xff0c;在进行轻量化处理时&#xff0c;顶点压缩是一种常用的技术方法。本文将…

Redis 十大数据类型

Redis数据类型都有哪些&#xff1f; Redis支持丰富的数据类型&#xff0c;那么具体在Redis7中都有哪些数据类型呢&#xff1f;请看下图&#xff1a; 官网介绍&#xff1a;https://redis.io/docs/data-types/。 其中&#xff0c;String、Hash、List、Set、Sorted Set等类型是大…

爬虫逆向实战(十五)--阿某某营登录

一、数据接口分析 主页地址&#xff1a;阿某某营 1、抓包 通过抓包可以发现登录接口是Users/Login 2、判断是否有加密参数 请求参数是否加密&#xff1f; 通过查看“载荷”模块可以发现有一个s加密参数 请求头是否加密&#xff1f; 无响应是否加密&#xff1f; 无cookie是…