• uni-app--》基于小程序开发的电商平台项目实战(三)


    🏍️作者简介:大家好,我是亦世凡华、渴望知识储备自己的一名在校大学生

    🛵个人主页亦世凡华、

    🛺系列专栏:uni-app

    🚲座右铭:人生亦可燃烧,亦可腐败,我愿燃烧,耗尽所有光芒。

    👀引言

            ⚓经过web前端的学习,相信大家对于前端开发有了一定深入的了解,今天我开设了uni-app专栏,主要想从移动端开发方向进一步发展,而对于我来说写移动端博文的第二站就是uni-app开发,希望看到我文章的朋友能对你有所帮助。

    今天开始使用 vue3 + uni-app 搭建一个电商购物的小程序,因为文章会将项目的每一个地方代码的书写都会讲解到,所以本项目会分成好几篇文章进行讲解,我会在最后一篇文章中会将项目代码开源到我的GitHub上,大家可以自行去进行下载运行,希望本文章对有帮助的朋友们能多多关注本专栏,学习更多前端uni-app知识。然后开篇先简单介绍一下本项目用到的技术栈都有哪几个方面(阅读此次项目实践文章能够学习到的技术):

    uni-app:跨平台的应用开发框架,基于vue.js可以一套代码同时构建运行在多个平台。

    pnpm:高性能、轻量级npm替代品,帮助开发人员更加高效地处理应用程序的依赖关系。

    vue3:vue.js最新版本的用于构建用户界面的渐进式JavaScript框架。

    typescript:JavaScript的超集,提供了静态类型检查,使得代码更加健壮。

    pinia:vue3构建的Vuex替代品,具有响应式能力,提供非常简单的 API,进行状态管理。

    uni-ui:基于vue.js和uni-app的前端UI组件库,开发人员可以快速地构建跨平台应用程序。

    如果是第一次接触uni-app并且想学习uni-app的朋友,我是不建议直接从此次实战项目开始看起,可以先阅读一下我以前的基础文章:什么是uniapp?如何开发uniapp?按部就班的学习可以让学习变得更轻松更容易上手哦,闲话少说我们直接开始今天的uni-app实战篇。

    目录

    实现上拉触底

    实现下拉刷新

    生成骨架屏

    热门推荐详情实现

    分页条件设置


    实现上拉触底

    在上一章节我们已经实现首页静态模块的搭建,接下来我们需要加载猜你喜欢的更多相关的数据,这里需要借助上拉触底的功能,因为滚动容器内包裹着猜你喜欢的组件,所以我们还需要通过父调子的方法来拿到相应的组件实例,这里我们先实现上拉触底的具体操作:

    这里我们需要在滚动容器当中添加 scrolltolower 函数来触发上拉触底的事件:

    接下来我们需要在调用上拉触底事件的时候,调用猜你喜欢组件内容的方法,这里需要我们将猜你喜欢的组件调用数据方法先暴露出来:

    然后通过 InstanceType 用于获取 Swiper 这个类的实例类型。 

    1. // 组件实例类型
    2. export type SwGuessInstance = InstanceType<typeof SwGuess>

    然后通过ref获取 SwGuess 组件的相应实例,之后便可以调用SwGuess组件当中的方法:

    1. // 滚动触底事件函数
    2. let guessRef = ref<SwGuessInstance>() // 获取猜你组件实例
    3. const onScrolltolower = () => {
    4. guessRef.value?.getGuess()
    5. }

    父组件调用子组件获取猜你喜欢函数的方法之后,当我们进行上拉触底的时候,该函数就会再次杯执行,如下:

    接下来对猜你喜欢的接口函数进行修改,我们之前编写的接口仅仅是获取默认第一页的数据而已,这里我们还需要传入可选参数页码page和页数pageSize,如下:

    1. /** 通用分页参数类型 */
    2. export type PageParams = {
    3. /** 页码:默认值为 1 */
    4. page?: number
    5. /** 页大小:默认值为 10 */
    6. pageSize?: number
    7. }

    接下来我们就需要对猜你喜欢的接口函数进行相应的修改了:

    1. /* *
    2. * 获取首页猜你喜欢的接口函数
    3. */
    4. export const getHomeGoodsGuessLike = (data?: PageParams) => {
    5. return http<PageResult<GuessItem>>({
    6. method: 'GET',
    7. url: '/home/goods/guessLike',
    8. data,
    9. })
    10. }

    编写完相应的接口函数之后,接下来我们需要在相应的猜你喜欢的组件中对猜你喜欢的接口函数传入相应的参数数据,然后对相应的数据进行一个数组的push,然后在进行一个页码数据的累加,因为页码的接口类型是可选参数,直接进行累加的话会ts类型报错,这里我们需要将可选参数变为必选参数,所以这里使用了必须类型的Required泛型方式,如下:

    1. // 获取猜你喜欢数据
    2. let pageParmas: Required<PageParams> = {
    3. page: 1,
    4. pageSize: 10,
    5. }
    6. let guessList = ref<GuessItem[]>([]) // 猜你喜欢数据列表
    7. const getHomeGoodsGuessLikeData = async () => {
    8. const res = await getHomeGoodsGuessLike(pageParmas)
    9. // guessList.value = res.result.items
    10. guessList.value.push(...res.result.items)
    11. // 页码累加
    12. pageParmas.page++
    13. }

    这里我们还需要对分页进行一个条件的判断,因为数据可能是有限的,如果我们不加以限制的话数据可能就会一直无限的循环下去,这里需要我们进行数据总数的一个判断,其对应的逻辑如下:

    这里通过设置一个结束标记来判断当前的页码是否小于总页码数,如果已经或等于的话,这里就借助uni-app提供的一个弹出消息框来提醒用户,当前的数据已经全部加载完毕了:

    1. // 设置一个结束标记
    2. let finish = ref(false)
    3. let guessList = ref<GuessItem[]>([]) // 猜你喜欢数据列表
    4. const getHomeGoodsGuessLikeData = async () => {
    5. if (finish.value) {
    6. return uni.showToast({
    7. title: '没有更多数据了~',
    8. icon: 'none',
    9. })
    10. }
    11. const res = await getHomeGoodsGuessLike(pageParmas)
    12. // guessList.value = res.result.items
    13. guessList.value.push(...res.result.items)
    14. if (pageParmas.page < res.result.pages) {
    15. // 页码累加
    16. pageParmas.page++
    17. } else {
    18. finish.value = true
    19. }
    20. }

    呈现的效果如下:

    实现下拉刷新

    实现下拉刷新需要借助的 refresher-enabled 属性来实现,其默认为false,这里我们在滚动容器中填写该属性即可,然后再通过自定义下拉刷新函数来设置相应的规则:

    自定义下拉刷新函数,这里我们把首页每个模块获取到的数据的函数再重新的调用一下:

    1. // 自定义下拉刷新
    2. const onRefresherrefresh = () => {
    3. getHomeBannerData() // 轮播图数据
    4. getHomeCategoryData() // 分类数据
    5. getHomeHotData() // 猜你喜欢数据
    6. }

    最终呈现的结果如下:

    虽然我们实现了下拉刷新后,数据的重新加载变化,但是下拉刷新的状态还是存在一直没消失,这里我们需要对其进行处理一下,通过 refresher-triggered 属性设置其下拉刷新的状态,如下:

    然后通过函数的调用时机,巧妙在数据加载完成之后再关闭下拉刷新的动画效果:

    1. // 设置下拉刷新状态
    2. let isTriggered = ref(false)
    3. // 自定义下拉刷新
    4. const onRefresherrefresh = async () => {
    5. // 开启动画
    6. isTriggered.value = true
    7. // 加载数据
    8. await getHomeBannerData() // 轮播图数据
    9. await getHomeCategoryData() // 分类数据
    10. await getHomeHotData() // 猜你喜欢数据
    11. // 加载数据完成关闭动画
    12. isTriggered.value = false
    13. }

    虽然我们实现了下拉刷新的效果,但是这个存在着一个性能问题,就是需要按个等每个数据都加载完成之后才会结束下拉刷新的效果:

    为了避免这个问题,我们可以借助es6语法的Promise.all()方法,等所有异步函数都加载完才执行

    1. // 设置下拉刷新状态
    2. let isTriggered = ref(false)
    3. // 自定义下拉刷新
    4. const onRefresherrefresh = async () => {
    5. // 开启动画
    6. isTriggered.value = true
    7. // 加载数据
    8. // await getHomeBannerData() // 轮播图数据
    9. // await getHomeCategoryData() // 分类数据
    10. // await getHomeHotData() // 猜你喜欢数据
    11. await Promise.all([getHomeBannerData(), getHomeCategoryData(), getHomeHotData()])
    12. // 加载数据完成关闭动画
    13. isTriggered.value = false
    14. }

    这样的方式就会很快结束我们下拉刷新的进程,提高了资源的利用效率:

    接下来我们还需要处理猜你喜欢组件下拉刷新时更新数据的方法,这里我们需要在猜你组件当中对我们当前的页码数据列表以及相应的结束标记都需要进行一个相应的重置,然后将我们重置的方法对外暴露出去:

    然后再在下拉刷新函数加载数据处,先调用猜你喜欢重置函数,然后再调用获取数据函数,这样的话当我们下拉查看到大于1的页码猜你喜欢的数据之后,回到首页再下拉刷新一下,猜你喜欢的数据又会重新加载到第一页:

    生成骨架屏

    骨架屏(Skeleton Screen)是一种应用于移动端和网页端的用户体验优化策略。它是在页面或者应用还未加载完毕时,先展示一个大致布局结构相同、内容却尚未加载完成的界面UI效果,让用户感知到应用正在加载中并且保证用户对内容的期待。之后再逐渐替换成真实数据。

    在微信开发者工具当中已经帮助我们提供了一键生成骨架屏的按钮,在模拟器的右下方就有按钮:

    我们点击生成骨架屏之后会生成相应的代码文件,这里我们需要将微信开发者工具生成的wxml和wxss文件转换成vue文件即可:

    接下来我们将生成好的vue文件导入到首页当中,然后通过v-if和v-else进行相应的判断

    我们在页面挂载的时候设置一个标记,开始时处于骨架屏状态,当页面同时都加载完成之后,接下来我们就可以将标记赋值为false然后关闭骨架屏展示相应的页面内容:

    1. // 标记是否在加载中
    2. let isLoading = ref(false)
    3. // 组件刚加载的时候调用
    4. onLoad(async () => {
    5. // 页码处于加载中
    6. isLoading.value = true
    7. await Promise.all([getHomeBannerData(), getHomeCategoryData(), getHomeHotData()])
    8. // 页面加载完毕
    9. isLoading.value = false
    10. })

    这里我们将微信开发者工具的网速调低,方便我们清晰的看到初始时骨架屏加载后的效果:

    热门推荐详情实现

    在之前我们已经实现了首页四个热门推荐详情数据的静态展示,接下来我们实现点击热门推荐进行页面跳转,实现热门推荐具体详情数据的展示,首先我们先在pages文件夹下新建uniapp页面,该页面会自动加载到我们的pages.json里面:

    页面新建好之后,接下来我们开始实现路由的跳转,因为热门推荐在首页的展示也是通过组件进行展示的,所以我们只要在热门推荐相关书写的组件中进行设置路由的跳转即可,这里我们借助uniapp中navigator固有的语法进行设置即可,具体的属性讲解这里就不再赘述了,想了解的朋友可以随时去官网进行查看,这里仅仅是简单提一下我们目前所使用的方式是什么:

    根据官方文档给我们提供的相关属性,这里我们就直接使用,并且巧妙的借助模板字符串进行动态的路由传参,将接口数据中特别分类热门推荐的数据type进行传递过去,便于区分我们点击的是谁

    接下来我们开始编写获取热门推荐相关数据的接口函数,这里函数设置的传递参数有两个,url路径是必传参数,data为可选参数为了后面设置分页数据加载做准备:

    1. import type { PageParams } from '@/types/global'
    2. import type { HotResult } from '@/types/hot'
    3. import { http } from '@/utils/http'
    4. type HotParams = PageParams & { subType?: string }
    5. // 热门推荐相关数据展示
    6. export const getHotRecommendAPI = (url: string, data?: HotParams) => {
    7. return http<HotResult>({
    8. method: 'GET',
    9. url,
    10. data,
    11. })
    12. }

    编写完接口函数之后,这里我们在我们新建的hot.vue页面进行接口函数的调用,然后通过ref响应式数据进行数据赋值:

    具体的页面布局设置如下,也是非常简单的动态绑定数据然后通过插值表达式进行数据的展示即可,这里简单提一下,我们在上面设置了高亮下标的标记,通过我们点击选项和我们当前的下标进行对比来展示不同的样式和不同的热门推荐数据,如下:

    1. <template>
    2. <view class="viewport">
    3. <view class="cover">
    4. <image class="imgae" :src="bannerPicture">image>
    5. view>
    6. <view class="tabs">
    7. <text
    8. v-for="(item, index) in subTypes"
    9. :key="item.id"
    10. class="text"
    11. :class="{ active: index === activeIndex }"
    12. @tap="activeIndex = index"
    13. >
    14. {{ item.title }}
    15. text>
    16. view>
    17. <scroll-view
    18. v-for="(item, index) in subTypes"
    19. :key="item.id"
    20. v-show="activeIndex === index"
    21. scroll-y
    22. class="scroll-view"
    23. >
    24. <view class="goods">
    25. <navigator
    26. hover-class="none"
    27. class="navigator"
    28. v-for="goods in item.goodsItems.items"
    29. :key="goods.id"
    30. :url="`/pages/goods/goods?id=${goods.id}`"
    31. >
    32. <image class="thumb" :src="goods.picture">image>
    33. <view class="name ellipsis">{{ goods.name }}view>
    34. <view class="price">
    35. <text class="symbol">¥text>
    36. <text class="number">{{ goods.price }}text>
    37. view>
    38. navigator>
    39. view>
    40. <view class="loading-text">正在加载...view>
    41. scroll-view>
    42. view>
    43. template>

    最终呈现的效果如下:

    分页条件设置

    当我们设置完初始的热门推荐详情页面之后,接下来我们需要开始为该详情页面进行设置相应的分页加载数据了,关于分页加载数据的讲解在上一篇文章讲解猜你喜欢数据的时候已经讲解过一遍了,当然这里在简单的进行讲解一下:

    首先我们需要先给滚动容器设置滚动触底事件,因为热门推荐详情页面有小tab按钮进行切换展示不同的热门推荐的数据,所以这里我们需要先获取我们点击当前热门推荐详情tab的下标,因为我们之前是通过v-show进行页面的切换展示的,不同的tab按钮展示的数据相互独立不会影响,所以不同担心。

    1. // 获取当前的选项
    2. const currsubTypes = subTypes.value[activeIndex.value]
    3. // 分页条件
    4. if (currsubTypes.goodsItems.page < currsubTypes.goodsItems.pages) {
    5. // 当前页码累加
    6. currsubTypes.goodsItems.page++
    7. } else {
    8. // 标记已结束
    9. currsubTypes.finish = true
    10. // 退出并提示消息
    11. return uni.showToast({ icon: 'none', title: '没有更多数据了~' })
    12. }

    根据条件的判断来确保是否要增加当前页码,然后接下来将增加的页码值再通过热门推荐的接口函数中进行传递再获取当前的数据,将获取到的数据再进行追加到我们设置好的参数中然后再进行调用相应的接口函数再一次获取数据,完整代码如下:

    1. // 自定义滚动触底事件
    2. const onScrolltolower = async () => {
    3. // 获取当前的选项
    4. const currsubTypes = subTypes.value[activeIndex.value]
    5. // 分页条件
    6. if (currsubTypes.goodsItems.page < currsubTypes.goodsItems.pages) {
    7. // 当前页码累加
    8. currsubTypes.goodsItems.page++
    9. } else {
    10. // 标记已结束
    11. currsubTypes.finish = true
    12. // 退出并提示消息
    13. return uni.showToast({ icon: 'none', title: '没有更多数据了~' })
    14. }
    15. // 调用API传参
    16. const res = await getHotRecommendAPI(currUrlMap!.url, {
    17. subType: currsubTypes.id,
    18. page: currsubTypes.goodsItems.page,
    19. pageSize: currsubTypes.goodsItems.pageSize,
    20. })
    21. // 新的列表选项
    22. const newsubTypes = res.result.subTypes[activeIndex.value]
    23. // 数据追加
    24. currsubTypes.goodsItems.items.push(...newsubTypes.goodsItems.items)
    25. }

    这里我们设置了一个结束标记finish,用来判断当前的数据是否已经加载完毕,因为subTypes本身是没有这个ts类型的,所以这里我们在之前设置ts类型基础之上,再添加一个:

    1. // 推荐选项
    2. const subTypes = ref<(SubTypeItem & { finish?: boolean })[]>([])

    然后这里我们就可以通过三元表达式进行判断当前的数据是否已经加载完毕了:

    <view class="loading-text">{{ item.finish ? '没有更多数据了~' : '正在加载...' }}view>

    这里还有一个小技巧,因为我们目前的分页数据有很多,当我们进行测试的时候需要不停的滚动数据,这里只要我们通过判断当前是否是开发还是生产环境,来动态的改变我们当前初始的页码值就可以方便的进行我们数据的测试了:

    如果是开发环境,测试页码是30否则就是1,所以当我们进行开发的时候就会从30页开始,打包上线之后,我们的初始页码数据就会从1进行开始了:

    最终呈现的效果如下:

    本项目首页的一些基本功能的搭建就讲解到这,下一篇文章将继续讲解项目的分类页码代码操作,关注博主学习更多前端uni-app知识,您的支持就是博主创作的最大动力!

  • 相关阅读:
    软件评测师之校验码
    【Java SE】多态的详解
    借助调试工具理解BLE协议_1.蓝牙简介和BLE工作流程
    JVM(3)
    配置基于 SSH 的跳转主机(跳板机)
    windows下配置maven
    05 参数的点估计
    【SpringBoot项目】SpringBoot项目-瑞吉外卖【day03】分类管理
    优秀的推荐系统架构与应用:从YouTube到Pinterest、Flink和阿里巴巴
    2022陕西清北录取人数排名,西工大附中遥遥领先,高新一中40人
  • 原文地址:https://blog.csdn.net/qq_53123067/article/details/133051134