[uni-app]小兔鲜-02项目首页

轮播图

轮播图组件需要在首页和分类页使用, 封装成通用组件

准备轮播图组件

<script setup lang="ts">
import type { BannerItem } from '@/types/home'
import { ref } from 'vue'
// 父组件的数据
defineProps<{list: BannerItem[]
}>()// 高亮下标
const activeIndex = ref(0)
// 索引变化
const onChange: UniHelper.SwiperOnChange = (ev) => {// ! 非空断言,主观上排除空值的情况activeIndex.value = ev.detail!.current
}
</script><template><view class="carousel"><swiper :circular="true" :autoplay="false" :interval="3000" @change="onChange"><swiper-item v-for="item in list" :key="item.id"><navigator url="/pages/index/index" hover-class="none" class="navigator"><image mode="aspectFill" class="image" :src="item.imgUrl"></image></navigator></swiper-item></swiper><!-- 指示点 --><view class="indicator"><textv-for="(item, index) in list":key="item.id"class="dot":class="{ active: index === activeIndex }"></text></view></view>
</template><style lang="scss">
/* 轮播图 */
@import '@/components/styles/XtxSwiper.scss';
</style>
  1. UniHelper 提供事件类型
  2. ? (可选链)允许前面表达式为空
  3. ! (非空断言)主观上排除掉空值情况
/** 首页-广告区域数据类型 */
export type BannerItem = {/** 跳转链接 */hrefUrl: string/** id */id: string/** 图片链接 */imgUrl: string/** 跳转类型 */type: number
}
  1. 统一管理项目需要使用的类型
import type { BannerItem } from '@/types/home'
import { http } from '@/utils/http'// 首页广告区域
export const getHomeBannerAPI = (distributionSite = 1) => {return http<BannerItem[]>({method: 'GET',url: '/home/banner',data: {distributionSite,},})
}
  1. 为接口数据进行类型限制
<script setup lang="ts">
import { onLoad } from '@dcloudio/uni-app'
import { ref } from 'vue'
import type { BannerItem } from '@/types/home'
import { getHomeBannerAPI } from '@/services/home'// 获取轮播图数据
const bannerList = ref<BannerItem[]>([])
const getHomeBannerData = async () => {const res = await getHomeBannerAPI()bannerList.value = res.result
}// 页面加载
onLoad(async () => {getHomeBannerData()
})
</script><template><!-- 自定义轮播图组件 --><XtxSwiper :list="bannerList" />
</template>
  1. 定义变量时要进行类型限制, 接口返回数据和定义的变量保持一致, 增强项目的健壮性
  2. 引入类型文件可以使用 ctrl + i 快捷键

配置全局组件的自动导入

{// 组件自动引入规则"easycom": {// 开启自动扫描"autoscan": true,// 以正则方式自定义组件匹配规则"custom": {// uni-ui 规则如下配置"^uni-(.*)": "@dcloudio/uni-ui/lib/uni-$1/uni-$1.vue",// 自定义 规则如下配置"Xtx(.*)": "@/components/Xtx$1.vue"}},... ...
}
  • 更改 easycom 配置需要重启服务

声明自定义组件的类型

import XtxSwiper from './components/XtxSwiper.vue'
import 'vue'
declare module 'vue' {export interface GlobalComponents {XtxSwiper: typeof XtxSwiper}
}
  • 通过 declare 指定 GlobalComponents 就可以定义全局组件的类型
  • 更多配置查看 Volar官网

分类导航

准备分类组件, 只有首页使用

<script setup lang="ts">
import type { CategoryItem } from '@/types/home'defineProps<{list: CategoryItem[]
}>()
</script><template><view class="category"><navigatorclass="category-item"hover-class="none"url="/pages/index/index"v-for="item in list":key="item.id"><image class="icon" :src="item.icon"></image><text class="text">{{ item.name }}</text></navigator></view>
</template><style lang="scss">
/* 前台类目 */
@import '../styles/category.scss';
</style>

使用分类组件

/** 首页-前台类目数据类型 */
export type CategoryItem = {/** 图标路径 */icon: string/** id */id: string/** 分类名称 */name: string
}
import type { CategoryItem } from '@/types/home'
import { http } from '@/utils/http'// 首页分类数据
export const getHomeCategoryAPI = () => {return http<CategoryItem[]>({method: 'GET',url: '/home/category/mutli',})
}
<script setup lang="ts">
import { ref } from 'vue'
import type { CategoryItem } from '@/types/home'
import { getHomeCategoryAPI } from '@/services/home'
import CategoryPanel from './components/CategoryPanel.vue'// 获取分类数据
const categoryList = ref<CategoryItem[]>([])
const getCategoryData = async () => {const res = await getHomeCategoryAPI()categoryList.value = res.result
}</script><template><!-- 分类组件 --><CategoryPanel :list="categoryList" />
</template><style lang="scss">
page {background-color: #f3f3f3;
}
</style>
  1. 小程序页面根标签是page, 类似于网页的body标签

效果展示

热门推荐

准备热门推荐组件, 只有首页使用

<script setup lang="ts">
import type { HotItem } from '@/types/home'// 定义 props 接收数据
defineProps<{list: HotItem[]
}>()
</script><template><!-- 推荐专区 --><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/hot/hot?type=${item.type}`" class="cards"><imagev-for="src in item.pictures":key="src"class="image"mode="aspectFit":src="src"></image></navigator></view></view>
</template><style lang="scss">
/* 热门推荐 */
@import '../styles/hot.scss';
</style>

使用推荐组件

/*** 首页-热门推荐数据类型*/
export type HotItem = {/** 说明 */alt: string/** id */id: string/** 图片集合[ 图片路径 ] */pictures: string[]/** 跳转地址 */target: string/** 标题 */title: string/** 推荐类型 */type: string
}
import type { HotItem } from '@/types/home'
import { http } from '@/utils/http'// 热门推荐数据
export const getHomeHotAPI = () => {return http<HotItem[]>({method: 'GET',url: '/home/hot/mutli',})
}
<script setup lang="ts">
import { ref } from 'vue'
import type { HotItem } from '@/types/home'
import { getHomeHotAPI } from '@/services/home'
import HotPanel from './components/HotPanel.vue'// 获取热门推荐数据
const HotPanelList = ref<HotItem[]>([])
const getHomeHotData = async () => {const res = await getHomeHotAPI()HotPanelList.value = res.result
}
</script><template><!-- 热门推荐 --><HotPanel :list="HotPanelList" />
</template><style lang="scss">
page {background-color: #f3f3f3;
}
</style>

效果展示

猜你喜欢

需求分析

准备猜你喜欢组件

  • 猜你喜欢多个页面会用到
  • 定义组件的类型

  • 准备 scroll-view 滚动容器

  • 设置page 和 sroll-view样式

获取猜你喜欢数据

  • 封装请求API

  • 组件挂载完毕调用API

数据类型定义和列表渲染

分页准备工作

数据分页加载

分页条件判断

代码实现

猜你喜欢组件

<script setup lang="ts">
import { getHomeGoodsGuessAPI } from '@/services/home'
import type { PageParams } from '@/types/global'
import type { GuessItem } from '@/types/home'
import { onMounted, ref, defineExpose } from 'vue'// 分页参数
// Required工具函数: 把可选参数转为必选
const pageParams: Required<PageParams> = {page: 1,pageSize: 10,
}
// 枯竭标记
const finish = ref(false)
// 获取猜你喜欢数据
const guessList = ref<GuessItem[]>([])
const getHomeGoodsGuessLikeData = async () => {if (finish.value) {return uni.showToast({icon: 'none',title: '没有更多了...',})}const res = await getHomeGoodsGuessAPI(pageParams)// 数组累加guessList.value.push(...res.result.items)// 分页条件 (当前页面小于总页数)if (pageParams.page < res.result.pages) {// 页码累加pageParams.page++} else {finish.value = true}
}// 重置数据
const resetData = () => {guessList.value = []pageParams.page = 1finish.value = false
}// 组件挂载
onMounted(() => {getHomeGoodsGuessLikeData()
})// 对外暴漏
defineExpose({getMore: getHomeGoodsGuessLikeData,resetData,
})
</script><template><!-- 猜你喜欢 --><view class="caption"><text class="text">猜你喜欢</text></view><view class="guess"><navigatorclass="guess-item"v-for="item in guessList":key="item.id":url="`/pages/goods/goods?id=4007498`"><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><style lang="scss">
</style>
  1. 使用TS的 Required工具函数, 把可选参数转为必选

组件类型的声明

/*** declare module '@vue/runtime-core'*   现调整为* declare module 'vue'*/
import XtxGuess from './component/XtxGuess.vue'
import 'vue'
declare module 'vue' {export interface GlobalComponents {XtxGuess: typeof XtxGuess}
}// 组件实例类型
/*** InstanceType -> 获取组件实例的类型* typeof XtxGuess -> 获取组件的类型*/
export type XtxGuessInstance = InstanceType<typeof XtxGuess>
  1. 使用TS提供的InstanceType工具方法, 可以获取组件的实例类型

请求接口封装

import type { PageParams, PageResult } from '@/types/global'
import type { GuessItem,  } from '@/types/home'
import { http } from '@/utils/http'// 猜你喜欢数据
export const getHomeGoodsGuessAPI = (data?: PageParams) => {return http<PageResult<GuessItem>>({method: 'GET',url: '/home/goods/guessLike',data,})
}

数据类型的定义

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

使用组件

<script setup lang="ts">
import { ref } from 'vue'
import CustomNavbar from './components/CustomNavbar.vue'
import type { XtxGuessInstance } from '@/types/component'// 猜你喜欢的组件实例
const guessRef = ref<XtxGuessInstance>()// 滚动触底事件
const onScorlltolower = () => {guessRef.value.getMore()
}</script><template><!-- 自定义导航组件 --><CustomNavbar /><scroll-view@scrolltolower="onScorlltolower"class="scroll_view"scroll-y>  <!-- 猜你喜欢 --><XtxGuess ref="guessRef" /></scroll-view>
</template><style lang="scss">
page {background-color: #f3f3f3;height: 100%;display: flex;flex-direction: column;
}.scroll_view {flex: 1;
}
</style>
  1. 让页面page的高度为100%, 通过弹性布局, 让滚动容器自动占满页面剩余高度

下拉刷新

需求分析

开启下拉刷新

完成刷新逻辑

代码实现

使用scroll-view滚动容器

<script setup lang="ts">
// 获取轮播图数据
const getHomeBannerData = async () => {}// 获取分类数据
const getCategoryData = async () => {}// 获取热门推荐数据
const getHomeHotData = async () => {}// 下拉刷新
const isTriggered = ref(false)
const onRefresherrefresh = async () => {isTriggered.value = trueguessRef.value?.resetData()// 等待三个方法执行完毕,且三个方法同时执行await Promise.all([getHomeBannerData(),getCategoryData(),getHomeHotData(),guessRef.value?.getMore(),])isTriggered.value = false
}
</script><template><!-- 自定义导航组件 --><CustomNavbar /><scroll-view:refresher-enabled@refresherrefresh="onRefresherrefresh":refresher-triggered="isTriggered"scroll-yclass="scroll_view"@scrolltolower="onScorlltolower"><!-- 自定义轮播图组件 --><XtxSwiper :list="bannerList" /><!-- 分类组件 --><CategoryPanel :list="categoryList" /><!-- 热门推荐 --><HotPanel :list="HotPanelList" /><!-- 猜你喜欢 --><XtxGuess ref="guessRef" /></scroll-view>
</template>
  1. :refresher-enabled="true" // 开启下拉刷新
  2. @refresherrefresh="onRefresherrefresh" //绑定下拉事件
  3. :refresher-triggered="isTriggered" // 控制动画效果
  4. onScorlltolower // 触底加载更多
  5. Promise.all([]) // 把多个异步任务作为一组进行管理, 同时执行所有任务, 返回整组的执行情况

骨架屏

需求分析

准备骨架屏组件

  1. 小程序自动生成的骨架屏是整个页面的结构
  2. 骨架屏只需要填充动态加载的结构, 比如顶部的导航栏是固定结构, 我们按需一下

代码实现

<script setup lang="ts">
import { onLoad } from '@dcloudio/uni-app'
import { ref } from 'vue'
import PageSkeleton from './components/PageSkeleton.vue'// 控制骨架屏
const isLoading = ref(false)
onLoad(async () => {isLoading.value = trueawait Promise.all([getHomeBannerData(), getCategoryData(), getHomeHotData()])isLoading.value = false
})
</script><template><scroll-view><!-- 骨架屏 --><PageSkeleton v-if="isLoading" /><template v-else><!-- 自定义轮播图组件 --><XtxSwiper :list="bannerList" /><!-- 分类组件 --><CategoryPanel :list="categoryList" /><!-- 热门推荐 --><HotPanel :list="HotPanelList" /><!-- 猜你喜欢 --><XtxGuess ref="guessRef" /></template></scroll-view>
</template>

效果展示

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

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

相关文章

【React】Ant Design 5.x版本drawer抽屉黑边问题

环境 antd: ^5.14.1react: ^18 问题情况 <Drawer open{open} closable{false} mask{false} width{680}getContainer{props.getContainer || undefined}><p>Some contents...</p><p>Some contents...</p><p>Some contents...</p> …

时序数据库 TDengine 的入门体验和操作记录

时序数据库 TDengine 的学习和使用经验 什么是 TDengine &#xff1f;什么是时序数据 &#xff1f;使用RPM安装包部署默认的网络端口 TDengine 使用TDengine 命令行&#xff08;CLI&#xff09;taosBenchmark服务器内存需求删库跑路测试 使用体验文档纠错 什么是 TDengine &…

OpenAI GPT o1技术报告阅读(2)- 关于模型安全性的测试案例

✨报告阅读&#xff1a;使用大模型来学习推理(Reason) 首先是原文链接&#xff1a;https://openai.com/index/learning-to-reason-with-llms/ 接下来我们看一个简单的关于模型安全性的测试&#xff0c;当模型被问到一个有风险的话题时&#xff0c;会如何思考并回答用户呢&…

C++ | Leetcode C++题解之第421题数组中两个数的最大异或值

题目&#xff1a; 题解&#xff1a; struct Trie {// 左子树指向表示 0 的子节点Trie* left nullptr;// 右子树指向表示 1 的子节点Trie* right nullptr;Trie() {} };class Solution { private:// 字典树的根节点Trie* root new Trie();// 最高位的二进制位编号为 30static…

【linux】gcc makefile

&#x1f525;个人主页&#xff1a;Quitecoder &#x1f525;专栏&#xff1a;linux笔记仓 目录 01.gcc如何完成02.gcc选项03.函数库与动静态链接静态链接动态链接库文件特点和用途动态链接版本和兼容性 04.makefile自动推导 01.gcc如何完成 预处理(进行宏替换) 预处理功能主要…

828华为云征文|使用Flexus X实例创建FDS+Nginx服务实现图片上传功能

一、Flexus X实例 什么是Flexus X实例呢&#xff0c;这是华为云最新推出的云服务器产品&#xff0c;如下图&#xff1a; 华为云推出的Flexus云服务器X系列&#xff0c;是在华为顶尖技术团队&#xff0c;特别是荣获国家科技进步奖的领军人物顾炯炯博士及其团队的主导下精心研发…

通过document获取节点元素

1.层级节点 <ul><li id"li1">1</li><li>2</li><li id"li3">3</li><li>4</li><li>5</li></ul><script>//获取id名为li1的元素赋值给li1let li1document.getElementById(li…

Java语言程序设计基础篇_编程练习题**18.34 (游戏:八皇后问题)

目录 题目&#xff1a;**18.34 (游戏:八皇后问题) 代码示例 代码解析 输出结果 使用文件 题目&#xff1a;**18.34 (游戏:八皇后问题) 八皇后问题是要找到一个解决方案&#xff0c;将一个皇后棋子放到棋盘上的每行中&#xff0c;并且两个皇后棋子之间不能相互攻击。编写个…

基于C#+SQL Server2005(WinForm)图书管理系统

图书管理系统 一、 首先把数据库脚本贴出来(数据库名为library) USE [library] GO /****** Object: Table [dbo].[books] Script Date: 06/12/2016 11:27:12 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE TABLE [dbo].[books]([bNum] [nvarchar](10…

宝塔部署vue项目出现的各种问题

使用宝塔面板&#xff0c;网站页面&#xff0c;构建php静态网页 问题一&#xff1a;图片等静态资源无法加载 找到真正请求的url&#xff0c; 然后在项目目录下面创建对应的目录&#xff0c;将资源放入 问题二&#xff1a;刷新出现404 在这里任意位置添加 ## 添加上这个配…

socket.io-client实现实前后端时通信功能

这里我使用的后端 基于node.js的koa框架 前端使用的是vite {"name": "hou","version": "1.0.0","description": "","main": "app.js","scripts": {"test": "echo …

ARM单片机的内存分布(重要)

ARM单片机的内存分布&#xff08;重要&#xff09; 一、S32K344的内存布局 MEMORY {int_pflash : ORIGIN 0x00400000, LENGTH 0x003D4000 /* 4096KB - 176KB (sBAF HSE)*/int_dflash : ORIGIN 0x10000000, LENGTH 0x00020000 /* 128KB …

BUUCTF [SCTF2019]电单车详解两种方法(python实现绝对原创)

使用audacity打开&#xff0c;发现是一段PT2242 信号 PT2242信号 有长有短&#xff0c;短的为0&#xff0c;长的为1化出来 这应该是截获电动车钥匙发射出的锁车信号 0 01110100101010100110 0010 0前四位为同步码0 。。。中间这20位为01110100101010100110为地址码0010为功…

不靠学历,不拼年资,怎么才能月入2W?

之前统计局发布了《2023年城镇单位就业人员年平均工资情况》&#xff0c;2023年全国城镇非私营单位和私营单位就业人员年平均工资分别为120698元和68340元。也就是说在去年非私营单位就业人员平均月薪1W&#xff0c;而私营单位就业人员平均月薪只有5.7K左右。 图源&#xff1a;…

两数之和、三数之和、四数之和

目录 两数之和 题目链接 题目描述 思路分析 代码实现 三数之和 题目链接 题目描述 思路分析 代码实现 四数之和 题目链接 题目描述 思路分析 代码实现 两数之和 题目链接 LCR 179. 查找总价格为目标值的两个商品 - 力扣&#xff08;LeetCode&#xff09; 题目…

EfficientFormer实战:使用EfficientFormerV2实现图像分类任务(一)

摘要 EfficientFormerV2是一种通过重新思考ViT设计选择和引入细粒度联合搜索策略而开发出的新型移动视觉骨干网络。它结合了卷积和变换器的优势&#xff0c;通过一系列高效的设计改进和搜索方法&#xff0c;实现了在移动设备上既轻又快且保持高性能的目标。这一成果为在资源受…

Redis-01 入门和十大数据类型

Redis支持两种持久化方式&#xff1a;RDB持久化和AOF持久化。 1.RDB持久化是将Redis的数据以快照的形式保存在磁盘上&#xff0c;可以手动触发或通过配置文件设置定时触发。RDB保存的是Redis在某个时间点上的数据快照&#xff0c;可以通过恢复RDB文件来恢复数据。 2.AOF持久化…

力扣P1706全排列问题 很好的引入暴力 递归 回溯 dfs

代码思路是受一个洛谷题解里面大佬的启发。应该算是一个dfs和回溯的入门题目&#xff0c;很好的入门题目了下面我会先给我原题解思路我想可以很快了解这个思路。下面是我自己根据力扣大佬写的。 我会进行详细讲解并配上图辅助理解大家请往下看 #include<iostream> #inc…

初始MYSQL数据库(7)—— 视图

找往期文章包括但不限于本期文章中不懂的知识点&#xff1a; 个人主页&#xff1a;我要学编程(ಥ_ಥ)-CSDN博客 所属专栏&#xff1a; MYSQL 引言 前面我们学习MySQL数据库时&#xff0c;创建表之后&#xff0c;会在表中插入数据&#xff0c;在需要的时候&#xff0c;也会进行…

python文字转wav音频

借鉴博客 一.前期准备 1. pip install baidu-aip 2. pip install pydub 3. sudo apt-get install ffmpeg 二.代码 from aip import AipSpeech from pydub import AudioSegment import time#input your own APP_ID/API_KEY/SECRET_KEY APP_ID 14891501 API_KEY EIm2iXtvD…