🏍️作者简介:大家好,我是亦世凡华、渴望知识储备自己的一名在校大学生
🛵个人主页:亦世凡华、
🛺系列专栏: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实战篇。
目录
🍇设置tabbar
🍈自定义导航栏
🍉封装轮播图组件
🍊分类模块搭建
🍋热门推荐模块搭建
🍌猜你喜欢模块搭建
🏆文末送书(好书推荐)
🍇设置tabbar
uni-app设置的底部tabbar的方式与原生微信小程序类似,如果不了解什么是底部tabbar的朋友,那么我推荐你先看一下 tabBar底部栏 ,在uni-app中无非也是相同的操作,我们借助我们上文讲解的插件在pages文件夹下右键新建 uni-app 页面,
输入创建文件夹的名称,空格之后书写导航栏标题:
在pages.json会自动生成我们创建的文件的名称:
接下来在pages.json文件夹下设置tabBar属性的内容,这里要事先在一些图标库类似阿里云图标库找到相关的图标图片,这里不再赘述,代码如下:
// 设置TabBar
"tabBar": {
"color": "#333",
"selectedColor": "#008c8c",
"backgroundColor": "#eee",
"borderStyle": "white",
"list": [
{
"text": "首页",
"pagePath": "pages/home/home",
"iconPath": "static/tabs/home_default.png",
"selectedIconPath": "static/tabs/home_selected.png"
},
{
"text": "分类",
"pagePath": "pages/category/category",
"iconPath": "static/tabs/category_default.png",
"selectedIconPath": "static/tabs/category_selected.png"
},
{
"text": "购物车",
"pagePath": "pages/cart/cart",
"iconPath": "static/tabs/cart_default.png",
"selectedIconPath": "static/tabs/cart_selected.png"
},
{
"text": "我的",
"pagePath": "pages/my/my",
"iconPath": "static/tabs/user_default.png",
"selectedIconPath": "static/tabs/user_selected.png"
}
]
}
最终呈现的效果如下:
🍈自定义导航栏
比如说我们想设置首页独有的一个导航栏,我们可以在首页home文件夹下新建一个业务文件夹,里面存放这该页面的业务组件,比如我们想在首页自定义一下导航栏, 我们可以设置如下代码:
<template>
<view class="navbar">
<!-- logo文字 -->
<view class="logo">
<h2 class="logo-title">电商平台</h2>
<text class="logo-text">新鲜 · 亲民 · 快捷</text>
</view>
<!-- 搜索条 -->
<view class="search">
<text class="icon-search">搜索商品</text>
<text class="icon-scan"></text>
</view>
</view>
</template>
<script setup lang="ts"></script>
<style lang="scss" scoped>
/* 自定义导航条 */
.navbar {
background-image: url(@/static/images/navigator_bg.png);
background-size: cover;
position: relative;
display: flex;
flex-direction: column;
padding-top: 20px;
.logo {
display: flex;
align-items: center;
height: 64rpx;
padding-left: 30rpx;
.logo-title {
width: 126rpx;
height: 39rpx;
color: #fff;
}
.logo-text {
flex: 1;
line-height: 28rpx;
color: #fff;
margin: 2rpx 0 0 20rpx;
padding-left: 20rpx;
border-left: 1rpx solid #fff;
font-size: 26rpx;
}
}
.search {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 10rpx 0 26rpx;
height: 64rpx;
margin: 16rpx 20rpx;
color: #fff;
font-size: 28rpx;
border-radius: 32rpx;
background-color: rgba(255, 255, 255, 0.5);
}
.icon-search {
&::before {
margin-right: 10rpx;
}
}
.icon-scan {
font-size: 30rpx;
padding: 15rpx;
}
}
</style>
设置完组件之后,然后在home组件中引入该组件:
引入该组件之后,我们需要在pages.json文件中进行设置home首页的导航栏自定义:
设置完自定义之后,我们设置的导航栏组件会自动出现在小程序最顶部:
有个问题就是我们设置的自定义导航栏并不能适配任何手机,因为手机屏幕的宽高不同会导致自定义的导航栏会出现一些图文覆盖的画面,为了防止这种情况,我们需要先了解一个概念,如下:
安全区域:手机的安全区域(Safe Area)是指屏幕上可供应用程序内容使用的实际可视区域,不包括潜在的刘海、圆角等设备特定区域。
我们可以调用uni-app给我们提供的一个api来获取手机系统的一些信息
我们可以打印一下来看看该函数获取到的手机系统的数据:
这里将获取到数据进行样式进行一个动态的呈现,如下:
设置完获取手机机型来展示动态样式数据之后,即使你用了iPhone14 Pro Max效果也很好看:
🍉封装轮播图组件
因为这里我们设置的轮播图在整个项目的多处页面会用到,所以这里我们可以将轮播图设置为全局组件然后再在每个想使用的组件中进行引入便可以了。 如果对轮播图不清楚的朋友可以看看 官网
这里的组件我们设置为子组件,父组件通过传递一些props参数,然后通过数据的传递呈现出不同内容的轮播图组件:
<template>
<view class="carousel">
<!-- 轮播图区域 -->
<swiper indicator-dots autoplay :interval="3000" :duration="1000" circular :list="list">
<!-- 循环渲染轮播图的item项 -->
<swiper-item v-for="item in list" :key="item.id">
<view class="swiper-item">
<!-- 动态绑定图片的 src 属性 -->
<image :src="item.imgUrl" mode="aspectFill"></image>
</view>
</swiper-item>
</swiper>
</view>
</template>
<script setup lang="ts">
import type { BannerItem } from '@/types/home'
// 添加泛型参数来指定属性类型
defineProps<{
list: BannerItem[]
}>()
</script>
<style lang="scss">
/* 轮播图 */
.carousel {
height: 100%;
position: relative;
overflow: hidden;
transform: translateY(0);
background-color: #efefef;
.swiper-item,
image {
width: 100%;
height: 100%;
}
}
</style>
这里开始撰写相应的轮播图接口函数如下:
// 封装首页所有要使用的api函数
import type { BannerItem } from '@/types/home'
import { http } from '@/utils/http'
/**
* 获取首页广告区域的接口函数
* @param distributionSite 广告区域展示位置
*/
export const getHomeBanner = (distributionSite = 1) => {
return http<BannerItem[]>({
method: 'GET',
url: '/home/banner',
data: {
distributionSite,
},
})
}
接下来我们在首页开始调用相应的接口函数获取相应的轮播图数据,然后将获取到的数据通过props传递给全局轮播图组件:
<template>
<HomeNavbar></HomeNavbar>
<Swiper :list="bannerList" />
</template>
<script lang="ts" setup>
import { getHomeBanner } from '@/api/home'
import { onLoad } from '@dcloudio/uni-app'
import { ref } from 'vue'
import HomeNavbar from './components/HomeNavbar.vue'
import type { BannerItem } from '@/types/home'
let bannerList = ref<BannerItem[]>([])
// 获取首页banner数据
const getHomeBannerData = async () => {
const res = await getHomeBanner()
bannerList.value = res.result
}
// 组件刚加载的时候调用
onLoad(() => {
getHomeBannerData()
})
</script>
这里简单说一下,我们要根据接口函数获取到的数据编写相应的ts类型,如下:
/** 首页-广告区域数据类型 */
export type BannerItem = {
/** 跳转链接 */
hrefUrl: string
/** id */
id: string
/** 图片链接 */
imgUrl: string
/** 跳转类型 */
type: number
}
最终达到的效果如下:
🍊分类模块搭建
分类模块的搭建很简单,通过获取接口函数传递过来的数据,然后在首页通过调用该接口函数获取到的数据然后通过props父传子组件数据进行页面渲染即可,这里我们也是将分类模块单独抽离出来作为home的业务组件,这里我们先编写相应的接口函数,如下:
import { http } from '@/utils/http'
/* *
* 获取首页前台分类的接口函数
*/
export const getHomeCategory = () => {
return http({
method: 'GET',
url: '/home/category/mutli',
})
}
编写完接口函数之后,接下来我们在首页home组件中调用该接口函数并打印一下查看数据:
// 获取首页分类数据
const getHomeCategoryData = async () => {
const res = await getHomeCategory()
console.log(res)
}
// 组件刚加载的时候调用
onLoad(() => {
getHomeCategoryData()
})
可以看到我们已经获取到对应的接口函数的数据了,接下来我们需要通过返回给我们的数据编写相应的ts类型:
/** 首页-前台类目数据类型 */
export type CategoryItem = {
/** 图标路径 */
icon: string
/** id */
id: string
/** 分类名称 */
name: string
}
我们通过获取到的分类数据通过props传参传递给子组件CategoryPanel,如下:
<template>
<view class="category">
<view class="category-item" hover-class="none" v-for="item in list" :key="item.id">
<image class="icon" :src="item.icon" @tap="goCategory"></image>
<text class="text">{{ item.name }}</text>
</view>
</view>
</template>
<script setup lang="ts">
// 引入ts类型
import type { CategoryItem } from '@/types/home'
// 设置点击事件
const goCategory = () => {
uni.switchTab({
url: '/pages/category/category',
})
}
// 定义 props 接收数据
defineProps<{
list: CategoryItem[]
}>()
</script>
<style lang="scss">
/* 前台类目 */
.category {
margin: 20rpx 0 0;
padding: 10rpx 0;
display: flex;
flex-wrap: wrap;
min-height: 328rpx;
.category-item {
width: 150rpx;
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
box-sizing: border-box;
.icon {
width: 100rpx;
height: 100rpx;
}
.text {
font-size: 26rpx;
color: #666;
}
}
}
</style>
最终达到的效果如下:
🍋热门推荐模块搭建
热门推荐的模块搭建和分类模块搭建类似,通过接口函数调用相应的数据然后再在业务组件中进行一个渲染加载数据即可,这里我们需要先编写相应的接口函数:
/* *
* 获取首页热门推荐的接口函数
*/
export const getHomeHot = () => {
return http<HotItem[]>({
method: 'GET',
url: '/home/hot/mutli',
})
}
这里的HotItem是根据接口返回给我们的数据编写相应的ts类型的,这里简单提一下:
/** 首页-热门推荐数据类型 */
export type HotItem = {
/** 说明 */
alt: string
/** id */
id: string
/** 图片集合[ 图片路径 ] */
pictures: string[]
/** 跳转地址 */
target: string
/** 标题 */
title: string
/** 推荐类型 */
type: string
}
接下来在首页调用相应的接口函数来获取到数据:
// 获取热门推荐数据
let hotList = ref<HotItem[]>([])
const getHomeHotData = async () => {
const res = await getHomeHot()
hotList.value = res.result
}
// 组件刚加载的时候调用
onLoad(() => {
getHomeHotData()
})
这里通过props传参,将接口获取到的数据传递给业务组件当中去,然后通过插值语法展示:
<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" class="cards">
<image
v-for="src in item.pictures"
:key="src"
class="image"
mode="aspectFit"
:src="src"
></image>
</navigator>
</view>
</view>
</template>
<script setup lang="ts">
import type { HotItem } from '@/types/home'
// 定义props接收数据
defineProps<{
list: HotItem[]
}>()
</script>
最终的效果如下:
🍌猜你喜欢模块搭建
猜你喜欢的模块搭建和前面的类似,区别在于猜你喜欢这个组件是和轮播图一样,不仅仅只是首页模块才使用,所以这里外面需要将其设置为全局组件,命名规则是在轮播图我们已经进行设置了,开头必须是Sw,这里我们先开始便捷相应的接口函数:
/* *
* 获取首页猜你喜欢的接口函数
*/
export const getHomeGoodsGuessLike = () => {
return http<PageResult<GuessItem>>({
method: 'GET',
url: '/home/goods/guessLike',
})
}
这里的ts类型采用了泛型嵌套, GuessItem作为泛型T参数,成为items的数组内容数据
接下来我们调用相应的接口函数,然后进行数据的一个呈现:
<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?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"> 正在加载... </view>
</template>
<script setup lang="ts">
import { onMounted, ref } from 'vue'
// 获取猜你喜欢的接口函数数据
import { getHomeGoodsGuessLike } from '@/api/home'
import type { GuessItem } from '@/types/home'
// 获取猜你喜欢数据
let guessList = ref<GuessItem[]>([])
const getHomeGoodsGuessLikeData = async () => {
const res = await getHomeGoodsGuessLike()
guessList.value = res.result.items
}
// 组件挂载完毕
onMounted(() => {
getHomeGoodsGuessLikeData()
})
</script>
为了让我们自定义设置的导航栏处于顶部固定显示的效果,这里我们需要使用scroll-view实现设置滚动可视区域的范围,如下:
这里我们通过flex上下布局,然后让滚动区域占据可视区域,最大的宽度这里就设置80%,因为要刨去顶部导航栏的范围:
最终实现的效果如下,至此首页的基础静态搭建完成:
🏆文末送书(好书推荐)
博主最近发现了一个令人惊喜的消息!对于喜欢读书的朋友来说,我非常推荐这个前端书籍网站!在这里,你可以找到最新、最全的前端书籍,满足你对知识的渴望。
无论你是初学者还是资深开发者,这个网站都有适合你的书籍选择。最近也有很多优惠活动:
清华社【秋日阅读企划】领券立享优惠
IT好书 5折叠加10元 无门槛优惠券:https://u.jd.com/Yqsd9wj
活动时间:9月4日-9月17日,先到先得,快快来抢
更重要的是,博主特别为大家准备了一个惊喜活动!
只要在评论区留言 “ 人生苦短,我爱前端 ” ,博主将会抽取3位幸运儿,免费送出一本该网站出品的精选Vue.js书籍并包邮到你手中!
就算没有抽到的朋友也不要灰心,近期还有该网站也会有更多精彩活动,博主会一直关注。一旦有好的优惠活动会第一时间分享给大家,没有抽到这本书但也想购买的朋友,可以通过下方连接购买
📚 京东购买链接:《Vue.js从入门到精通(软件开发视频大讲堂)》
如果这篇文章的浏览量破3000的话,博主会继续给粉丝送书,大家可以选择自己想要的书籍,博主会尽量满足大家的需求,我会在底部设置一个投票,大家可以选择自己想要的书籍,当然大家也可以把想要的书打在评论区,下次送书说不定就是你想要的书籍哦!
提醒:大家别忘记了在评论区评论:人生苦短,我爱前端!参与抽奖哦。