学习目标:
-
掌握 luch-request 网络请求的用法
-
能够对 Pinia 进行初始化操作
-
掌握创建 Store 及数据操作的步骤
-
能够对 Pinia 数据进行持久化的处理
-
掌握用户登录的实现方法
一、项目启动
从零起步创建项目,完整的静态页面可以从 gitee 仓库获取。
1.1 创建项目
以 HBuilder X 的方式创建项目:
-
项目名称:优医咨询
-
Vue 版本:Vue3
-
模板:默认模板
1.1.1 .prettierrc
在项目根目录下创建 .prettierrc
文件,然后添加下述配置选项:
{ "printWidth": 80, "tabWidth": 2, "useTabs": false, "semi": false, "singleQuote": true, "vueIndentScriptAndStyle": true, }
上述配置内容是关于 Prettier 的常用的配置项,以后实际开发过程中可以根据需要逐步完善。
1.1.2 配置 tabBar
根据设计稿的要求配置 tabBar,首先通过 HBuilder X 新建 3 个页面,然后再配置 pages.json
文件。
共有4个页面,分别为:首页、健康百科、消息通知、我的,在课堂上统一约束目录的名称:首页对应 index、健康百科对应 wiki、消息通知对应 notify、我的对应 my 。
tabBar 用的图片在课程资料中可以找到,将其拷贝到项目的根目录下,然后在 pages.json
中进行配置:
{ "pages": [{ "path": "pages/index/index", "style": { "navigationBarTitleText": "优医咨询" } }, { "path": "pages/my/index", "style": { "navigationBarTitleText": "我的", "enablePullDownRefresh": false } }, { "path": "pages/notify/index", "style": { "navigationBarTitleText": "消息通知", "enablePullDownRefresh": false } }, { "path": "pages/wiki/index", "style": { "navigationBarTitleText": "健康百科", "enablePullDownRefresh": false } }], "globalStyle": { "navigationBarTextStyle": "black", "navigationBarTitleText": "优医咨询", "navigationBarBackgroundColor": "#fff", "backgroundColor": "#F8F8F8" }, "tabBar": { "color": "#6F6F6F", "selectedColor": "#6F6F6F", "borderStyle": "white", "list": [{ "text": "首页", "pagePath": "pages/index/index", "iconPath": "static/tabbar/home-default.png", "selectedIconPath": "static/tabbar/home-active.png" }, { "text": "健康百科", "pagePath": "pages/wiki/index", "iconPath": "static/tabbar/wiki-default.png", "selectedIconPath": "static/tabbar/wiki-active.png" }, { "text": "消息通知", "pagePath": "pages/notify/index", "iconPath": "static/tabbar/notify-default.png", "selectedIconPath": "static/tabbar/notify-active.png" }, { "text": "我的", "pagePath": "pages/my/index", "iconPath": "static/tabbar/my-default.png", "selectedIconPath": "static/tabbar/my-active.png" } ] }, "uniIdRouter": {} }
除了配置 tabBar
外,还要配置每个页面的导航栏的标题 navigationBarTitleText
及全局导航栏背景颜色 navigationBarBackgroundColor
为白色。
1.1.3 公共样式
在 App.vue 中配置公共 css 代码,不仅能精简代码,将来样式的维护也会更方便,这些公共样式是由开发者根据不同的项目需要自定义的,因此不同的项目或者不同开发者定义的公共样式是不一致的,本项目中我定义了以下部分的公共样式:
<!-- App.vue --> <script> // 省略这里的代码... </script> <style lang="scss"> image { vertical-align: middle; } button:after { display: none; } .uni-button { height: 88rpx; text-align: center; line-height: 88rpx; border-radius: 88rpx; color: #fff; font-size: 32rpx; background-color: #20c6b2; &[disabled], &.disabled { color: #fff !important; background-color: #ace8e0 !important; } } </style>
关于 scss 本项目定义了一个变量和一个混入,这个混入是用来处理文字溢出的,溢出的部分会显示 ...
来代替。
// uni.scss // 省略了默认生成的 scss 代码... $line: 2; @mixin text-overflow($line) { display: -webkit-box; -webkit-line-clamp: $line; -webkit-box-orient: vertical; text-overflow: ellipsis; overflow: hidden; }
1.1.4 引入字体图标
项目中即用到了单色图标,也用到了多色图标:
-
单色图标,将字体图标文件解压缩到 static/fonts 目录中,将 iconfont.css 重命名为 iconfont.scss
@font-face { font-family: 'iconfont'; src: url('/static/fonts/iconfont.ttf') format('truetype'); } .iconfont { font-family: 'iconfont' !important; font-size: 16px; font-style: normal; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } .icon-done:before { content: '\ea54'; } .icon-location:before { content: '\e6ea'; } .icon-edit:before { content: '\e6e9'; } .icon-shield:before { content: '\e6e8'; } .icon-checked:before { content: '\e6e5'; } .icon-box:before { content: '\e6e6'; } .icon-truck:before { content: '\e6e7'; }
图标成功导入项目后,在 App.vue 中导入自定义图标的样式文件
<!-- App.vue --> <script> // 省略这里的代码... </script> <style lang="scss"> // 单色图标 @import '@/static/fonts/iconfont.scss' // 以下部分代码省略... </style>
字体图标导入成功后要到页面测试一下图标是否能正常显示。
-
关于多色图标的使用在前面课程中已经介绍过了,关于图标的转换部分就不再演示了,我们直接将转换后代码引入项目中
先将生成的多色图标文件 color-fonts.scss
放到项目的根目录中,然后在 App.vue 中导入该文件
<!-- App.vue --> <script> // 省略这里的代码... </script> <style lang="scss"> // 单色图标 @import '@/static/fonts/iconfont.scss'; // 多色图标 @import './color-fonts.scss'; // 以下部分代码省略... </style>
字体图标导入成功后要到页面测试一下图标是否能正常显示。
1.1.5 网站图标
浏览器在加载网页时会在标签页位置展示一个小图标,我们来指定一下这个图标:
<!-- index.html --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <!-- 这里省略了部分代码... --> <!-- 这行代码用来指定网站图标 --> <link rel="shortcut icon" href="/favicon.ico" type="image/x-icon"> </head> <body> <div id="app"><!--app-html--></div> <script type="module" src="/main.js"></script> </body> </html>
1.2 公共封装
封装一系列的公共的方法,如网络请求、轻提示、日期时间处理等。
1.2.1 网络请求
小程序或 uni-app 提供了专门用于网络请求的 API ,但结合实际开发还需要扩展一些与业务相关的逻辑,如基地址、拦截器等功能,通常会对 uni.request
进行封装,luch-request
就是这样一个工具模块,它仿照 axios 的用法对 uni.request
进行二次封装,扩展了基地址、拦截器等业务相关的功能。
-
安装
luch-request
npm install luch-request
-
实例化并配置基地址,项目根目录新建 utils/http.js
// utils/http.js // 导入模块 import Request from 'luch-request' // 实例化网络请求 const http = new Request({ // 接口基地址 baseURL: 'https://t1ps66c7na.hk.aircode.run', }) // 导出配置好的模网络模块 export { http }
<!-- pages/test/index.vue --> <script setup> import { http } from '@/utils/http.js' function onButtonClick() { // 1. 普通用法 http.request({ url: '/echo', method: 'GET', header: { customHeader: '22222222' } }) } </script> <template> <view class="content"> <button @click="onButtonClick" type="primary">luch-request 测试</button> </view> </template>
-
配置请求拦截器
在请求之前执行一些逻辑,例如检测登录状态,添加自定义头信息等。
// utils/http.js // 导入模块 import Request from 'luch-request' // 实例化网络请求 const http = new Request({ // 接口基地址 baseURL: 'https://t1ps66c7na.hk.aircode.run', }) // 请求拦截器 http.interceptors.request.use( function (config) { // 定义头信息,并保证接口调用传递的头信息 // 能够覆盖在拦截器定义的头信息 config.header = { Authorization: '11111111', ...config.header, } return config }, function (error) { return Promise.reject(error) } ) // 导出配置好的模网络模块 export { http }
以上代码中要注意拦截器中配置的头信息不要将原有的头信息覆盖。
-
配置响应拦截器
// utils/http.js // 导入模块 import Request from 'luch-request' // 实例化网络请求 const http = new Request({ // 接口基地址 baseURL: 'https://t1ps66c7na.hk.aircode.run', }) // 请求拦截器 http.interceptors.request.use( function (config) { // 定义头信息,并保证接口调用传递的头信息 // 能够覆盖在拦截器定义的头信息 config.header = { Authorization: '11111111', ...config.header, } return config }, function (error) { return Promise.reject(error) } ) // 响应拦截器 http.interceptors.response.use( function ({ statusCode, data, config }) { // 解构出响应主体 return data }, function (error) { return Promise.reject(error) } ) // 导出配置好的模网络模块 export { http }
<!-- pages/test/index.vue --> <script setup> import { http } from '@/utils/http.js' async function onButtonClick() { // 1. 普通用法 const result = await http.request({ url: '/echo', method: 'GET', header: { customHeader: '22222222' } }) console.log(result) } </script> <template> <view class="content"> <button @click="onButtonClick" type="primary">luch-request 测试</button> </view> </template>
-
请求加载状态
在发请求之前展示一个加载提示框,请求结束后隐藏这个提示框,该部分的逻辑分别对应请求拦截器和响应拦截器,在请求拦截器中调用 uni.showLoading
在响应拦截器中调用 uni.hideLoading
。
在设置加载提示框之前先来了解一下 luch-request
提供的自定义配置参数的功能,即 custom
属性,该属性的用法如下:
// utils/http.js // 导入模块 import Request from 'luch-request' // 实例化网络请求 const http = new Request({ // 接口基地址 baseURL: 'https://t1ps66c7na.hk.aircode.run', custom: { abc: 123, loading: true } }) // 省略以下部分代码...
局部配置了相同的自定义参数时会覆盖全局配置的自定义参数
<!-- pages/test/index --> <script setup> import { http } from '@/utils/http.js' async function onButtonClick() { // 1. 普通用法 const result = await http.request({ // 省略部分代码... // 局部配置自定义参数 custom: { abc: 123, }, // 省略部分代码... }) console.log(result) } </script>
在了解自定义参数的使用后,我们来自定义一个能控制是否需要 loading 提示框的属性,全局默认为 true
。
// utils/http.js // 导入模块 import Request from 'luch-request' // 实例化网络请求 const http = new Request({ // 接口基地址 baseURL: 'https://t1ps66c7na.hk.aircode.run', custom: { loading: true } }) // 请求拦截器 http.interceptors.request.use( function (config) { // 显示加载状态提示 if (config.custom.loading) { uni.showLoading({ title: '正在加载...', mask: true }) } // 定义头信息,并保证接口调用传递的头信息 // 能够覆盖在拦截器定义的头信息 config.header = { Authorization: '11111111', ...config.header, } return config }, function (error) { return Promise.reject(error) } ) // 响应拦截器 http.interceptors.response.use( function ({ statusCode, data, config }) { // 隐藏加载状态提示 uni.hideLoading() // 解构出响应主体 return data }, function (error) { return Promise.reject(error) } ) // 导出配置好的模网络模块 export { http }
到此关于网络请求的基本用法就封装完毕了,后续会补充登录权限检测的业务逻辑。
1.2.2 轻提示
uni-app 提供了 uni.showToast
API 用于轻提示,但其传的参数比较复杂,通过封装来简化参数的传递。
新建 utils/utils.js
/** * 项目中会用的一系列的工具方法 */ u