🏍️作者简介:大家好,我是亦世凡华、渴望知识储备自己的一名在校大学生
🛺系列专栏: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实战篇。
目录
在个人中心模块搭建时,这里我们打算使用自定义导航栏来设置个人模块的搭建,如果想使用自定义导航栏,我们需要在 pages.json 文件设置如下属性:
设置完自定义导航栏之后,导航栏的内容就会被组件的内容自动顶上去了,所以接下来我们就需要设置页面就可以了,在个人中心模块有两个页面需要展示,一个是登录成功的页面另一个是未登录的页面,两个页面下面都是有相应的猜你喜欢组件的相关内容,这里我们思考了一下,猜你喜欢组件的使用频率相对来说较高,所以我们把公共模块的组件代码封装成全局组件来进行公共的复用:
- import { ref } from 'vue'
- import type { SwGuessInstance } from '@/types/components'
-
- /**
- * 猜你喜欢组合式函数
- */
- export const useGuessList = () => {
- // 获取猜你喜欢组件实例
- const guessRef = ref<SwGuessInstance>()
- // 滚动触底事件
- const onScrolltolower = () => {
- guessRef.value?.getGuess()
- }
- // 返回 ref 和事件处理函数
- return {
- guessRef,
- onScrolltolower,
- }
- }
个人中心模块展示不同页面的条件是根据仓库中用户信息是否存在展示的,这里需要直接调用该模块即可,通过v-if和v-else来进行相应的展示,给该滚动容器设置自定义上拉触底事件:
因为我们把自定义上拉触底事件封装成公共组件,这里直接调用即可:
const { guessRef, onScrolltolower } = useGuessList()
既然我们把猜你喜欢的公共代码模块封装成公共组件,在首页的相关猜你喜欢组件内容的模块代码也可以直接删掉换上公共代码的调用即可:
最终呈现的结果如下:
关于设置页面一般用户不会主动去点击,这也就导致设置页面的停留次数相对较少,这里我们可以将设置页面设置一下分包,这里需要了解以下两个概念:
小程序分包:将小程序的代码分割成多个部分,分别打包成多个小程序包,减少小程序的加载时间,提高用户体验。
分包预下载:在进入小程序某个页面时,由框架自动预下载可能需要的分包,提升进入后续分包页面时的加载速度。
关于分包的其他相关概念这里不再赘述,想了解更深一点的朋友可以参考我之前的文章:分包
在 vscode 中我们新建分包页面,插件已经给我们提供好了方式,只需要在相应的文件夹下鼠标右键选择新建uniapp页面(分包)即可,如下:
为了避免和主页面pages文件夹搞混淆,这里我们可以在src文件夹下重新创建一个新的文件,然后在该文件夹下再重新创建分包文件:
当我们创建分包页面的时候,相应的的在pages.json文件夹下也会生成相应的分包加载规则:
接下来我们在个人中心的设置按钮处设置相应的跳转路径:
通过如下代码来搭建设置页面的基础样式:
- <template>
- <view class="viewport">
-
- <view class="list" v-if="true">
- <navigator url="/pagesMember/address/address" hover-class="none" class="item arrow">
- 我的收货地址
- navigator>
- view>
-
- <view class="list">
- <button hover-class="none" class="item arrow" open-type="openSetting">授权管理button>
- <button hover-class="none" class="item arrow" open-type="feedback">问题反馈button>
- <button hover-class="none" class="item arrow" open-type="contact">联系我们button>
- view>
-
- <view class="list">
- <navigator hover-class="none" class="item arrow" url=" ">关于小程序navigator>
- view>
-
- <view class="action">
- <view class="button">退出登录view>
- view>
- view>
- template>
呈现的效果如下:
搭建完相关页面之后,接下来在 pages.json 文件夹下设置分包预下载规则,关于该小程序分包预下载的相关规则这里不再赘述,想了解的朋友可以直接查看官网,这里直接给出该规则:
- // 分包预下载规则
- "preloadRule": {
- "pages/my/my" :{
- "network": "all",
- "packages": ["subpackage"]
- }
- }
分包规则设置完成之后,接下来我们就可以看到,当我们访问其他页面的时候页面是正常加载的,当我们访问个人中心页面的时候,分包会自动预下载方便我们进入的分包页面:
接下我们给退出登录设置点击事件,这里我们给其相应的点击事件设置模态框提示用户退出登录的相关确定,相关代码如下:
这里设置一下条件渲染,当用户未登录的情况下,需要将收获地址和相应的退出登录按钮进行相应的删除,代码如下:
最后呈现的结果如下:
个人信息页是用户点击个人中心页面的用户头像或更改头像昵称跳转到个人信息页面,这里的个人信息页面也采用分包的方式,所以这里我们只需要在专门设置分包的文件夹下设置新文件profile来作为个人信息页的页面,创建页面之后在个人中心页面的相应位置设置跳转链接:
接下来编写相应的接口函数来获取个人信息数据:
- // 封装个人信息数据接口
- import type { ProfileDetail } from '@/types/member'
- import { http } from '@/utils/http'
-
- /**
- * 获取个人信息
- */
- export const getMemberProfileAPI = () => {
- return http<ProfileDetail>({
- method: 'GET',
- url: '/member/profile',
- })
- }
这里的ts类型可以将公共部分的参数分离出去,然后将独有的参数和公共的部分合并在一起:
- /** 通用的用户信息 */
- type BaseProfile = {
- /** 用户ID */
- id: number
- /** 头像 */
- avatar: string
- /** 账户名 */
- account: string
- /** 昵称 */
- nickname?: string
- }
-
- /** 小程序登录 登录用户信息 */
- export type LoginResult = BaseProfile & {
- /** 手机号 */
- mobile: string
- /** 登录凭证 */
- token: string
- }
-
- /** 个人信息 用户详情信息 */
- export type ProfileDetail = BaseProfile & {
- /** 性别 */
- gender?: Gender
- /** 生日 */
- birthday?: string
- /** 省市区 */
- fullLocation?: string
- /** 职业 */
- profession?: string
- }
编写完相应的接口之后,接下来就需要进行引入该接口函数然后将返回的数据存储在ref数据中:
- import { ref } from 'vue'
- // 导入接口函数
- import { getMemberProfileAPI } from '@/api/profile'
- import { onLoad } from '@dcloudio/uni-app'
- import type { ProfileDetail } from '@/types/member'
-
- // 获取屏幕边界到安全区域距离
- const { safeAreaInsets } = uni.getSystemInfoSync()
- // 获取个人信息的接口
- const profile = ref<ProfileDetail>()
- const getMemberProfileData = async () => {
- const res = await getMemberProfileAPI()
- profile.value = res.result
- }
- // 页面加载时候调用
- onLoad(() => {
- getMemberProfileData()
- })
将ref数据通过插值表达式和v-bind数据绑定来动态的呈现数据,具体的页面结果如下:
修改用户头像:这里修改图片的方式我们需要借助uniapp相应的api,其相应的参数讲解这里不再赘述,想了解的可以参考相应的官方文档即可。其具体的代码如下:
- // 修改头像
- const onAvatarChange = () => {
- // 调用拍照/选择图片API
- uni.chooseMedia({
- count: 1, // 文件个数
- mediaType: ['image'], // 文件类型
- success: (res) => {
- console.log(res)
- },
- })
- }
结果如下:
接下来借助uniapp中的上传文件的api进行相应的操作,完整的代码如下:
- // 修改头像
- const onAvatarChange = () => {
- // 调用拍照/选择图片API
- uni.chooseMedia({
- count: 1, // 文件个数
- mediaType: ['image'], // 文件类型
- success: (res) => {
- // 本地路劲
- const { tempFilePath } = res.tempFiles[0]
- // 文件上传
- uni.uploadFile({
- url: '/member/profile/avatar', // 接口地址
- name: 'file', // 接口参数
- filePath: tempFilePath, // 文件路径
- success: (res) => {
- if (res.statusCode === 200) {
- const avatar = JSON.parse(res.data).result.avatar
- // 个人信息页数据更新
- profile.value!.avatar = avatar
- // store头像更新
- memberStore.profile!.avatar = avatar
- uni.showToast({ icon: 'success', title: '更新成功' })
- } else {
- uni.showToast({ icon: 'error', title: '出现错误' })
- }
- },
- })
- },
- })
- }
最后的结果如下:
接下来开始收集相应的表单数据进行数据的更新,首先这里我们先编写相应的接口函数,如下:
- /**
- * 修改个人信息
- * @param data 请求体参数
- */
- export const putMemberProfileAPI = (data: ProfileParams) => {
- return http<ProfileDetail>({
- method: 'PUT',
- url: '/member/profile',
- data,
- })
- }
昵称方面的数据这里我们之间使用v-model双向数据绑定即可,使用非空断言避免其初始值不存在也就是undefined的情况,如下:
关于性别的单选框和生日方面的内容,这里直接在相应的表单中设置change函数监听其变化:
将动态改变的值存放在响应式ref数据当中:
- // 修改性别
- const onGenderChange: UniHelper.RadioGroupOnChange = (ev) => {
- profile.value.gender = ev.detail.value as Gender
- }
- // 修改生日
- const onBirthdayChange: UniHelper.DatePickerOnChange = (ev) => {
- profile.value.birthday = ev.detail.value
- }
选择城市方面这里也是采用相应的change事件监听其变化:
修改城市的方面需要提供两个数据,一个是前端需要的数据另一个是后端需要的数据:
- // 修改城市
- let fullLocationCode: [string, string, string] = ['', '', '']
- const onFullLocationChange: UniHelper.RegionPickerOnChange = (ev) => {
- // 这是前端页面需要的详细文字数据
- profile.value.fullLocation = ev.detail.value.join(' ')
- // 这是后端需要地区编码的数据
- fullLocationCode = ev.detail.code!
- }
最后给保存按钮设置点击函数,该函数里面调用相应的修改个人信息的接口函数,将我们收集的表单数据作为参数传递给接口函数当中:
- // 点击按钮保存表单
- const onSubmit = async () => {
- // 结构相应的数据
- const { nickname, gender, birthday } = profile.value
- const res = await putMemberProfileAPI({
- nickname,
- gender,
- birthday,
- provinceCode: fullLocationCode[0],
- cityCode: fullLocationCode[1],
- countyCode: fullLocationCode[2],
- })
- // 更新store昵称
- memberStore.profile!.nickname = res.result.nickname
- uni.showToast({ icon: 'success', title: '保存成功' })
- setTimeout(() => {
- uni.navigateBack()
- }, 400)
- }
最终呈现的结果如下:
本项目个人中心页面、个人信息页面的一些基本功能的搭建就讲解到这,下一篇文章将继续讲解项目其他页面操作,关注博主学习更多前端uni-app知识,您的支持就是博主创作的最大动力!