uni-app(优医咨询)项目实战 - 第3天

发布于:2024-05-05 ⋅ 阅读:(36) ⋅ 点赞:(0)

学习目标:

  • 掌握 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 引入字体图标

项目中即用到了单色图标,也用到了多色图标:

  1. 单色图标,将字体图标文件解压缩到 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>

字体图标导入成功后要到页面测试一下图标是否能正常显示。

  1. 关于多色图标的使用在前面课程中已经介绍过了,关于图标的转换部分就不再演示了,我们直接将转换后代码引入项目中

先将生成的多色图标文件 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 进行二次封装,扩展了基地址、拦截器等业务相关的功能。

  1. 安装 luch-request

npm install luch-request
  1. 实例化并配置基地址,项目根目录新建 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>
  1. 配置请求拦截器

在请求之前执行一些逻辑,例如检测登录状态,添加自定义头信息等。

// 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 }

以上代码中要注意拦截器中配置的头信息不要将原有的头信息覆盖。

  1. 配置响应拦截器

// 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>
  1. 请求加载状态

在发请求之前展示一个加载提示框,请求结束后隐藏这个提示框,该部分的逻辑分别对应请求拦截器和响应拦截器,在请求拦截器中调用 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

网站公告

今日签到

点亮在社区的每一天
去签到