[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.rhkb.cn/news/433364.html

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

相关文章

影响6个时序Baselines模型的代码Bug

前言 我是从去年年底开始入门时间序列研究&#xff0c;但直到最近我读FITS这篇文章的代码时&#xff0c;才发现从去年12月25号就有人发现了数个时间序列Baseline的代码Bug。如果你已经知道这个Bug了&#xff0c;那可以忽略本文&#xff5e; 这个错误最初在Informer&#xff0…

安科瑞Acrel-1000DP分布式光伏监控系统在鄂尔多斯市鄂托克旗巴音乌苏六保煤矿5MW分布式光伏项目中的应用

安科瑞 华楠 摘 要&#xff1a;分布式光伏发电就是将太阳能光伏板分散布置在各个区域&#xff0c;通过小规模、模块化的方式实现电能的并网或独立使用&#xff0c;这种发电方式具有就近发电、就近并网、就近转换、就近使用的特点。近年来&#xff0c;技术进步和政策支持推动了光…

Python在AI中的应用--使用决策树进行文本分类

Python在AI中的应用--使用决策树进行文本分类 文本分类决策树什么是决策树 scikit算法 使用scikit的决策树进行文章分类一个文本分类的Python代码使用的scikit APIs说明装入数据集决策树算法类类构造器&#xff1a; 构造决策树分类器产生输出评估输出结果分类准确度分类文字评估…

计算机前沿技术-人工智能算法-大语言模型-最新论文阅读-2024-09-22

计算机前沿技术-人工智能算法-大语言模型-最新论文阅读-2024-09-22 引言: 全球最热销的国产游戏-《黑神话: 悟空》不仅给世界各地玩家们带来愉悦&#xff0c;而且对计算机人工智能研究也带来新的思考。在本期的论文速读中&#xff0c;我们带来一篇关于视觉语言模型&#xff0…

漫步者头戴式耳机好用吗?漫步者、西圣、万魔顶级机型测评对比

现在市面上有很多头戴式耳机&#xff0c;它们都基本精进主动降噪功能&#xff0c;以让大家在生活中能更少受到噪音的干扰&#xff0c;所以对于有降噪需求的人来说&#xff0c;头戴式耳机就是很适合他们的一种耳机。作为一名数码测评博主&#xff0c;也有很多人问我漫步者头戴式…

C++的vector优化

1、C中的动态数组一般是特指vector类 2、vector需要优化的原因之一是当我们push_back元素到数组中时&#xff0c;如果原来分配给动态数组的内存不够用了&#xff0c;那么就会找一块更大的内存空间分配给数组&#xff0c;把旧的内容复制到新的内存中去&#xff0c;这就是导致程…

大数据处理从零开始————3.Hadoop伪分布式和分布式搭建

1.伪分布式搭建&#xff08;不会用&#xff0c;了解就好不需要搭建&#xff09; 这里接上一节。 1.1 伪分布式集群概述 伪分布式集群就是只有⼀个服务器节点的分布式集群。在这种模式中&#xff0c;我们也是只需要⼀台机器。 但与本地模式不同&#xff0c;伪分布式采⽤了分布式…

C++简单缓冲区类设计

目录 1.引言 2.静态缓冲区 3.动态缓冲区 4.数据引用类 5.自动数据引用类 6.几种缓冲区的类关系图 7.注意事项 8.完整代码 1.引言 在C中&#xff0c;设计静态和动态缓冲区类时&#xff0c;需要考虑的主要差异在于内存管理的方式。静态缓冲区类通常使用固定大小的内存区域…

红绿灯倒计时读秒数字识别系统源码分享

红绿灯倒计时读秒数字识别检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of …

Power Automate 设置流Owner不生效的bug

在查找某个功能没生效时&#xff0c;定位到是一个Power automate的流停了&#xff0c;查看原因是因为创建流的owner被disable了 但是当把流的owner更新为可用的用户时&#xff0c;流依旧没被触发&#xff0c;触发的条件很简单&#xff0c;某个表的记录创建时&#xff0c;因为是…

Java流程控制语句——条件控制语句详解(附有流程图)#Java条件控制语句有哪些?#if-else、switch

在 Java 编程中&#xff0c;条件控制语句用于控制程序的执行路径&#xff0c;决定根据某些条件来选择执行某段代码或跳过某段代码。它们是 Java 编程的重要组成部分&#xff0c;帮助开发者根据不同的输入、状态或数据流来编写更加灵活和动态的代码。在本文中&#xff0c;我们将…

CORE MVC 过滤器 (筛选器)

MVC FrameWork MVCFramework MVC Core 过滤器 分 同步、异步 1、 授权筛选器 IAuthorizationFilter&#xff0c;IAsyncAuthorizationFilter 管道中运行的第一类筛选器&#xff0c;用来确定发出请求的用户是否有权限发出当前请求 2、资源筛选器 IResourceFilter &#xff0c;…

部分监督多器官医学图像分割中的标记与未标记分布对齐|文献速递--基于多模态-半监督深度学习的病理学诊断与病灶分割

Title 题目 Labeled-to-unlabeled distribution alignment for partially-supervised multi-organ medical image segmentation 部分监督多器官医学图像分割中的标记与未标记分布对齐 01 文献速递介绍 多器官医学图像分割&#xff08;Mo-MedISeg&#xff09;是医学图像分析…

【Python报错已解决】ModuleNotFoundError: No module named ‘tensorflow‘

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 专栏介绍 在软件开发和日常使用中&#xff0c;BUG是不可避免的。本专栏致力于为广大开发者和技术爱好者提供一个关于BUG解决的经…

DAY16||513.找树左下角的值 |路径总和|从中序与后序遍历序列构造二叉树

513.找树左下角的值 题目&#xff1a;513. 找树左下角的值 - 力扣&#xff08;LeetCode&#xff09; 给定一个二叉树的 根节点 root&#xff0c;请找出该二叉树的 最底层 最左边 节点的值。 假设二叉树中至少有一个节点。 示例 1: 输入: root [2,1,3] 输出: 1示例 2: 输入: […

Techub专访顾荣辉教授:解密CertiK的安全战略路线

当 Web3 安全审计公司还在争抢审计份额时&#xff0c;CertiK 已经开始将目光瞄准即将进军 Web3 的传统商业巨头。CertiK 不仅在传统行业进行白帽行动获得如苹果公司的官方感谢&#xff0c;还是 Web3 行业唯一一家拥有 SOC 2 和 ISO 认证的 Web3 的安全公司。基于此&#xff0c;…

猫头虎 分享已解决Bug: || Module not found: Can‘t resolve ‘react‘ 解决方案

&#x1f42f;猫头虎 分享已解决Bug&#xff1a; || Module not found: Cant resolve react 解决方案 摘要: 今天猫头虎带大家解决一个常见的前端问题&#xff0c;尤其是在 React 项目中&#xff0c;很多开发者在安装依赖包时&#xff0c;遇到过 Module not found: Cant resol…

裁剪视频如何让画质不变?一文教会你

当我们想要从一段视频中提取精华&#xff0c;裁剪视频就成了必不可少的技能。 但是&#xff0c;如何做到在裁剪过程中不损害画质&#xff0c;保持视频原有的清晰度和流畅度呢&#xff1f; 这不仅需要技巧&#xff0c;还需要对视频编辑有一定的了解。 本文将为你介绍四种裁剪…

基于SSM的图书管理管理系统的设计与实现 (含源码+sql+视频导入教程)

&#x1f449;文末查看项目功能视频演示获取源码sql脚本视频导入教程视频 1 、功能描述 基于SSM的图书管理管理系统4拥有两种角色&#xff0c;用户可以浏览评论图书、登录注册&#xff0c;管理员可以进行图书馆管理、用户管理、分类管理等功能 1.1 背景描述 图书书店销售管理…

jenkins声明式流水线语法详解

最基本的语法包含 pipeline&#xff1a;所有有效的声明式流水线必须包含在一个 pipeline 块中stages&#xff1a;包含一系列一个或多个stage指令stage&#xff1a;stage包含在stages中进行&#xff0c;比如某个阶段steps&#xff1a;在阶段中具体得执行操作&#xff0c;一个或…