vu3+pinia+uni-UI——Ts
工程结构解析
├── .husky # Git Hooks
├── .vscode # VS Code 插件 + 设置
├── dist # 打包文件夹(可删除重新打包)
├── src # 源代码
│ ├── components # 全局组件
│ ├── composables # 组合式函数
| |———pagesMember #分包页面
│ ├── pages # 主包页面
│ ├── index # 首页
│ ├── category # 分类页
│ ├── cart # 购物车
│ ├── my # 我的
│ └── login # 登录页
│ ├── services # 所有请求
│ ├── static # 存放应用引用的本地静态资源的目录
│ ├── images # 普通图片
│ └── tabs # tabBar 图片
│ ├── stores # 全局 pinia store
│ ├── modules # 模块
│ └── index.ts # store 入口
│ ├── styles # 全局样式
│ └── fonts.scss # 字体图标
│ ├── types # 类型声明文件
│ └── component.d.ts # 全局组件类型声明
│ ├── utils # 全局方法(比如请求封装)
│ ├── App.vue # 入口页面
│ ├── main.ts # Vue初始化入口文件
│ ├── pages.json # 配置页面路由等页面类信息
│ ├── manifest.json # 配置appid等打包信息
│ └── uni.scss # uni-app 内置的常用样式变量
├── .editorconfig # editorconfig 配置
├── .eslintrc.cjs # eslint 配置
├── .prettierrc.json # prettier 配置
├── .gitignore # git 忽略文件
├── index.html # H5 端首页
├── package.json # package.json 依赖
├── tsconfig.json # typescript 配置
└── vite.config.ts # vite 配置
- 运行程序
# 微信小程序端
npm run dev:mp-weixin
# H5端
npm run dev:h5
# App端
需 HbuilderX 工具,运行 - 运行到手机或模拟器
1.创建
1.通过 HbuilderX 创建 uni-app vue3 项目
我们先来认识 uni-app 项目的目录结构。
├─pages 业务页面文件存放的目录
│ └─index
│ └─index.vue index页面
├─static 存放应用引用的本地静态资源的目录(注意:静态资源只能存放于此)
├─unpackage 非工程代码,一般存放运行或发行的编译结果
├─index.html H5端页面
├─main.js Vue初始化入口文件
├─App.vue 配置App全局样式、监听应用生命周期
├─pages.json **配置页面路由、导航栏、tabBar等页面类信息**
├─manifest.json **配置appid**、应用名称、logo、版本等打包信息
└─uni.scss uni-app内置的常用样式变量
uni-app 和原生小程序开发区别
开发区别
uni-app 项目每个页面是一个 .vue
文件,数据绑定及事件处理同 Vue.js
规范:
- 属性绑定
src="{ { url }}"
升级成:src="url"
- 事件绑定
bindtap="eventName"
升级成@tap="eventName"
,支持()传参 - 支持 Vue 常用指令
v-for
、v-if
、v-show
、v-model
等
其他区别补充
- 调用接口能力,建议前缀
wx
替换为uni
,养成好习惯,支持多端开发。 <style>
页面样式不需要写scoped
,小程序是多页面应用,页面样式自动隔离。- 生命周期分三部分:应用生命周期(小程序),页面生命周期(小程序),组件生命周期(Vue)
2.命令行创建 uni-app 项目
优势
通过命令行创建 uni-app 项目,不必依赖 HBuilderX,TypeScript 类型支持友好。
创建其他版本可查看:uni-app 官网
常见问题
- 运行
npx
命令下载失败,请尝试换成手机热点重试 - 换手机热点依旧失败,请尝试从国内备用地址下载
- 在
manifest.json
文件添加 小程序 AppID 用于真机预览 - 运行
npx
命令需依赖 NodeJS 环境,NodeJS 下载地址 - 运行
git
命令需依赖 Git 环境,Git 下载地址
编译和运行 uni-app 项目
- 安装依赖
pnpm install
- 编译成微信小程序
pnpm dev:mp-weixin
- 导入微信开发者工具
温馨提示
编译成 H5 端可运行 pnpm dev:h5
通过浏览器预览项目。
3.用 VS Code 开发 uni-app 项目
为什么选择 VS Code?
- VS Code 对 TS 类型支持友好,前端开发者主流的编辑器
- HbuilderX 对 TS 类型支持暂不完善,期待官方完善 👀
用 VS Code 开发配置
项目采用 Vue3 + TS 开发 uni-app 项目,所以需要分别安装 Vue3 + TS 插件 和 uni-app 插件。
安装 Vue3 + TS 插件
注意事项
没开发过 Vue3 + TS 项目的小伙伴注意,需要先安装 Vue3 和 TS 的插件,并完成以下配置 👇
- 安装 Vue Language Features (Volar) :Vue3 语法提示插件
- 安装 TypeScript Vue Plugin (Volar) :Vue3 的 TS 插件
- 工作区禁用 Vetur 插件(Vue2 插件和 Vue3 插件冲突)
- 工作区禁用 @builtin typescript 插件(禁用后自动开启 Vue3 的 TS 托管模式)
配合微信开发者工具使用
- 运行程序
# 微信小程序端
npm run dev:mp-weixin
# H5端
npm run dev:h5
# App端
需 HbuilderX 工具,运行 - 运行到手机或模拟器
微信开发者工具导入 /dist/dev/mp-weixin
打包目录,可以预览
2.配置uni-ui组件
1.安装组件库
pnpm i @dcloudio/uni-ui 或 yarn add @dcloudio/uni-ui
组件使用的入门教程 | uni-app官网 (dcloud.net.cn)
2.配置全局自动导入 配置easycom(组件自动导入),就不用自己导入了
使用 npm
安装好 uni-ui
之后,需要配置 easycom
规则,让 npm
安装的组件支持 easycom
打开项目根目录下的 pages.json
并添加 easycom
节点:
//组件自动引入规则
"easycom": {
"autoscan": true,
"custom": {
// uni-ui 规则如下配置 以 uni 开头的组件,在 components 目录中自动查找
"^uni-(.*)": "@dcloudio/uni-ui/lib/uni-$1/uni-$1.vue",
// 以 Xtx 开头的组件,在 components 目录中自动查找自定义的组件
"^Xtx(.*)": "@/components/Xtx$1.vue"
}
},
"pages": [
配置pinia -持久化-请求封装-1.拦截器2.请求函数
为什么封装?
uni.request的success函数只表示 服务器请求成功,没处理响应状态码,业务中使用不方便
axios函数是状态码是2xx,才调用resolve函数,表示获取数据成功,业务中使用更精确
// src/utils/http.ts
import { useMemberStore } from '@/stores'
// 请求基地址
const baseURL = 'https://pcapi-xiaotuxian-front-devtest.itheima.net'
// 拦截器配置
const httpInterceptor = {
// 拦截前触发
invoke(options: UniApp.RequestOptions) {
// 1. 非 http 开头需拼接地址
if (!options.url.startsWith('http')) {
options.url = baseURL + options.url
}
// 2. 请求超时
options.timeout = 10000
// 3. 添加小程序端请求头标识
options.header = {
'source-client': 'miniapp',
...options.header, //如果有保留下来
}
// 4. 添加 token 请求头标识
const memberStore = useMemberStore()
const token = memberStore.profile?.token
if (token) {
options.header.Authorization = token
}
},
}
// 拦截 request 请求
uni.addInterceptor('request', httpInterceptor)
// 拦截 uploadFile 文件上传
uni.addInterceptor('uploadFile', httpInterceptor)
//小程序中普通请求,和uploadFile 文件上传请求要分开
/**
* 请求函数
* @param UniApp.RequestOptions
* @returns Promise
* 1. 返回 Promise 对象,用于处理返回值类型
* 2. 获取数据成功
* 2.1 提取核心数据 res.data
* 2.2 添加类型,支持泛型
* 3. 获取数据失败
* 3.1 401错误 -> 清理用户信息,跳转到登录页
* 3.2 其他错误 -> 根据后端错误信息轻提示
* 3.3 网络错误 -> 提示用户换网络
*/
//封装以http取代uni.request,返回的是promise 方便async await
// 定义泛型
type Data<T> = {
code: string
msg: string
result: T
}
export const http = <T>(options: UniApp.RequestOptions) => {
return new Promise<Data<T>>((resolve, reject) => {
uni.request({
...options,
// 请求成功
success(res) {
// 状态码 2xx,参考 axios 的设计,uni没实现
if (res.statusCode >= 200 && res.statusCode < 300) {
//提取核心数据
//401是有服务器响应,要在success判断
resolve(res.data as Data<T>)
} else if (res.statusCode === 401) {
// 401错误 -> 清理用户信息,跳转到登录页
const memberStore = useMemberStore()
memberStore.clearProfile()
uni.navigateTo({ url: '/pages/login/login' })
reject(res)
} else {
// 其他错误 -> 根据后端错误信息轻提示
uni.showToast({
icon: 'none',
title: (res.data as Data<T>).msg || '请求错误',
})
reject(res)
}
},
// 响应失败
fail(err) {
uni.showToast({
icon: 'none',
title: '网络错误,换个网络试试',
})
//标记错误,不要往下执行了
reject(err)
},
})
})
}
```js
自定义导航配置
json
自定义导航配置
// src/pages.json
{
"path": "pages/index/index",
"style": {
"navigationStyle": "custom", // 隐藏默认导航
"navigationBarTextStyle": "white",
"navigationBarTitleText": "首页"
}
}
动态设置安全距离
<!-- src/pages/index/componets/CustomNavbar.vue -->
<script>
// 获取屏幕边界到安全区域距离
const { safeAreaInsets } = uni.getSystemInfoSync()
</script>
<template>
<!-- 顶部占位 -->
<view class="navbar" :style="{ paddingTop: safeAreaInsets?.top + 'px' }">
<!-- ...省略 -->
</view>
</template>
自定义导航栏,位置不随滚动而滚动
利用scroll-view flex
在类型定义中,对应通用ts类型,可以用泛型进行复用,泛型相当于参数
触底发起请求,获取数据
我们将请求定义在组件上,而不是定义在页面上?
因为我们还需要使用,就不用再次请求了,而是每当使用组件就发起请求
在滚动触底调用方法 @scrolltolower="onScrolltolower"
父调子中的方法,利用模板ref获取组件实例
子组件内部方法默认封闭,需要暴露
//暴露
defineExpose({
getMore: getHomeGoodsGuessLikeData //名字太长,给个别名
})
分页加载
传递参数
步骤
升级API函数
分页条件
加载页码超过页总数,后端没有数据是空数组,再发请求不合理,所以要加分页条件
优化
下拉刷新
基于滚动容器的
下拉刷新实际上是在用户操作下拉交互时重新调用接口,然后将新获取的数据再次渲染到页面中。
操作步骤
基于 scroll-view
组件实现下拉刷新,需要通过以下方式来实现下拉刷新的功能。
- 配置
refresher-enabled
属性,开启下拉刷新交互 - 监听
@refresherrefresh
事件,监听用户是否执行了下拉操作 - 配置
refresher-triggered
属性,关闭下拉状态(自己不会自动关闭)
使用async await 等待请求执行完,再往下执行,必须等第一个,然后第二个。。。。。
性能优化
** Promise.all() 让这些请求同时走,都走完再往后走**
下拉刷新-猜你喜欢组件
对于组件自身维护数据,刷新要重置数据,重置的在子组件,要父调子
使用
骨架屏
利用微信开发者工具生成
在vue中使用与原生微信小程序不同
1.分离窗口
5.使用个变量判断加载状态
做tabbar改变样式
1.
一级分类获取二级分类
向组件传参数
自定义事件
实现子调父,自定义事件可以实现子组件给父组件传递数据
父组件内部给子组件绑定一个自定义事件,在子组件内部触发这个自定义事件
登录
真实开发
设置分包
对不常使用的进行分包,例如设置
- 按模块管理页面,方便项目维护。
- 减少主包体积,用到的时候再加载分包,属于性能优化解决方案。
小程序分包:将小程序代码分割成多个部分,分别打包成多个小程序包,减少小程序加载时间。分包的默认不加载,使用时再加载,但使用时还需等待?
优化:
分包预下载:在进入小程序某个页面时,由框架自动预下载可能需要的分包,提高进入后续分包页面时的启动速度
步骤 1.新建分包页面 2.配置分包预下载
新建文件夹pagesMember用来放分包页面
不放在pages里,防止与主包混淆
分包:按照项目业务模块划分,如会员模块分包,订单模块分包
表单验证
利用uni-forms/uni-forms-item组件
插件市场
小程序tabbar页:小程序跳转tabbar页,会关闭其他非tabbar页页面,所以小程序tabbar页没有后退按钮,想实现跳转tabbar页,我们要再建个一模一样的普通页,