uni-app多端跨平台开发从入门到企业级实战 读书笔记

1. 入门篇

1.1 uni-app 简介

1.1.1 什么是 uni-app

uni-app 是 DCloud 公司推出的一款使用 Vue.js 开发所有前端应用的跨平台框架,开发者编写一套代码,可发布到 iOS、Android、H5、以及各种小程序(微信/支付宝/百度/头条/QQ/钉钉/淘宝)等多个平台。uni-app 基于 Vue.js 框架,结合了小程序的开发规范,提供了一套统一的开发体验。

1.1.2 uni-app 的技术架构

uni-app 采用了分层架构设计,从底层到上层依次为:

  • 运行时核心:基于不同平台的原生引擎,提供统一的运行时环境
  • 编译器:将 Vue.js 代码编译为各平台可执行的代码
  • 框架层:提供 Vue.js 语法支持和跨平台 API 封装
  • 组件库:提供丰富的 UI 组件和业务组件
  • 插件系统:支持扩展平台能力和功能

1.1.3 uni-app 的工作原理

uni-app 的工作原理主要包括以下几个方面:

  1. 代码编译:开发者编写的 Vue.js 代码通过编译器编译为各平台的原生代码
  2. 运行时适配:运行时根据不同平台的特性进行适配
  3. API 封装:封装各平台的原生 API,提供统一的调用接口
  4. 组件渲染:根据不同平台的渲染机制,将组件渲染为原生 UI

1.1.4 uni-app 的优势

  • 开发效率高:一套代码多端运行,减少重复开发,提高开发效率
  • 性能优异:底层使用原生渲染,性能接近原生应用,部分场景甚至超过原生
  • 生态丰富:集成了大量的 UI 组件和插件,满足各种开发需求
  • 开发成本低:使用 Vue.js 语法,学习成本低,开发者可以快速上手
  • 跨平台能力强:支持 10+ 个平台,覆盖移动端、Web 和小程序
  • 原生能力:可以通过插件机制调用各平台的原生能力
  • 热更新:支持 App 端热更新,无需重新提交应用商店

1.1.5 uni-app 的应用场景

  • 企业级移动应用:需要跨平台部署,降低开发成本
  • 电商应用:需要多端覆盖,提高用户触达率
  • 内容类应用:需要快速迭代,多端同步更新
  • 工具类应用:需要轻量级部署,快速上线
  • 小程序开发:需要同时开发多个平台的小程序
  • SaaS 应用:需要为不同客户提供定制化的移动应用
  • 内部管理系统:需要快速开发,多端访问

1.1.6 uni-app 与其他跨平台框架的对比

框架优势劣势
uni-app支持平台多,性能优异,生态丰富部分平台特性需要条件编译
Flutter性能优异,UI 一致性好学习成本高,生态相对较弱
React Native生态丰富,社区活跃性能不如原生,平台差异大
IonicWeb 技术栈,学习成本低性能不如原生,体验差异大
原生开发性能最佳,体验最好开发成本高,多端维护困难

1.2 开发环境搭建

1.2.1 安装 HBuilderX

HBuilderX 是 DCloud 公司推出的一款轻量级、高性能的前端开发工具,专为 uni-app 开发优化,集成了代码编辑器、模拟器、打包工具等功能。

安装步骤

  1. 访问 HBuilderX 官网
  2. 下载对应操作系统的安装包(推荐下载 App 开发版,包含 uni-app 相关插件)
  3. 解压并安装 HBuilderX
  4. 首次启动时,HBuilderX 会自动安装必要的插件

HBuilderX 配置优化

  • 编辑器配置:在「工具」→「设置」→「编辑器」中配置字体、缩进、代码提示等
  • 插件安装:在「工具」→「插件安装」中安装 uni-ui、uni-stat 等插件
  • 快捷键配置:在「工具」→「设置」→「快捷键」中配置常用快捷键

1.2.2 创建 uni-app 项目

方法一:使用 HBuilderX 创建

步骤

  1. 打开 HBuilderX
  2. 点击「文件」→「新建」→「项目」
  3. 选择「uni-app」项目类型
  4. 填写项目名称、存储位置
  5. 选择模板(默认模板、Hello uni-app、空项目、TypeScript 模板等)
  6. 点击「创建」按钮

方法二:使用命令行工具创建

uni-app 提供了命令行工具 @dcloudio/uni-cli,可以通过 npm 安装并使用:

1
2
3
4
5
6
7
8
9
10
11
# 安装命令行工具
npm install -g @dcloudio/uni-cli

# 创建项目
uni init my-project

# 进入项目目录
cd my-project

# 安装依赖
npm install

项目初始化高级选项

  • TypeScript 支持:选择 TypeScript 模板或手动配置 tsconfig.json
  • ESLint 配置:在项目根目录创建 .eslintrc.js 文件
  • Prettier 配置:在项目根目录创建 .prettierrc 文件
  • Git 初始化:使用 git init 初始化 Git 仓库

1.2.3 运行项目

运行到浏览器

  1. 点击工具栏的「运行」按钮
  2. 选择「运行到浏览器」→ 选择浏览器
  3. 浏览器会自动打开项目页面

运行到小程序模拟器

  1. 安装对应小程序的开发工具(微信开发者工具、支付宝开发者工具等)
  2. 在小程序开发工具中开启「端口号」设置(微信开发者工具:设置 → 安全设置 → 开启服务端口)
  3. 在 HBuilderX 中点击「运行」→ 选择对应小程序
  4. HBuilderX 会自动启动小程序开发工具并加载项目

运行到手机

  1. Android 设备

    • 连接手机到电脑
    • 开启 USB 调试模式(设置 → 开发者选项 → USB 调试)
    • 在 HBuilderX 中点击「运行」→ 选择「运行到 Android App 基座」
    • 手机会自动安装并启动 uni-app 基座应用
  2. iOS 设备

    • 连接 iPhone/iPad 到 Mac 电脑
    • 在 HBuilderX 中点击「运行」→ 选择「运行到 iOS App 基座」
    • 需要在 Xcode 中配置开发者证书

运行到云端模拟器
HBuilderX 提供了云端模拟器功能,可以在没有真机的情况下测试应用:

  1. 在 HBuilderX 中点击「运行」→ 选择「运行到云端模拟器」
  2. 选择对应的平台和设备类型
  3. 等待云端模拟器启动并加载项目

1.2.4 开发工具配置

微信开发者工具配置

  • 开启服务端口:设置 → 安全设置 → 开启服务端口
  • 关闭 ES6 转 ES5:设置 → 项目设置 → 关闭「ES6 转 ES5」
  • 关闭代码压缩:设置 → 项目设置 → 关闭「代码压缩」

HBuilderX 性能优化

  • 关闭不必要的插件
  • 调整编辑器缓存大小
  • 使用 SSD 存储提高读写速度

多环境配置
可以在项目中配置多个环境(开发、测试、生产),通过不同的配置文件区分:

1
2
3
4
5
6
7
8
9
10
11
12
// config/env.js
module.exports = {
development: {
baseURL: 'https://dev-api.example.com'
},
test: {
baseURL: 'https://test-api.example.com'
},
production: {
baseURL: 'https://api.example.com'
}
};

1.3 项目结构

1.3.1 基本目录结构

uni-app 项目采用了清晰的目录结构,便于开发者组织代码和资源:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
├── api/             # API 接口封装
├── components/ # 组件目录
├── config/ # 配置文件目录
├── filters/ # 过滤器目录
├── mixins/ # 混入目录
├── pages/ # 页面目录
├── services/ # 服务层目录
├── static/ # 静态资源目录
├── store/ # 状态管理目录
├── styles/ # 样式文件目录
├── utils/ # 工具函数目录
├── unpackage/ # 打包输出目录
├── App.vue # 应用入口文件
├── main.js # 应用入口文件
├── manifest.json # 应用配置文件
├── pages.json # 页面配置文件
├── uni.scss # 全局样式文件
├── package.json # 项目依赖配置
└── tsconfig.json # TypeScript 配置文件

1.3.2 目录结构优化

企业级项目目录结构最佳实践

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
├── api/                 # API 接口封装
│ ├── modules/ # 按模块划分的 API
│ ├── request.js # 请求封装
│ └── index.js # API 导出
├── components/ # 组件目录
│ ├── base/ # 基础组件
│ ├── business/ # 业务组件
│ └── common/ # 通用组件
├── config/ # 配置文件目录
│ ├── env.js # 环境配置
│ ├── api.js # API 配置
│ └── theme.js # 主题配置
├── filters/ # 过滤器目录
├── mixins/ # 混入目录
├── pages/ # 页面目录
│ ├── home/ # 首页相关页面
│ ├── user/ # 用户相关页面
│ └── product/ # 产品相关页面
├── services/ # 服务层目录
│ ├── auth.js # 认证服务
│ ├── user.js # 用户服务
│ └── product.js # 产品服务
├── static/ # 静态资源目录
│ ├── images/ # 图片资源
│ ├── fonts/ # 字体资源
│ └── icons/ # 图标资源
├── store/ # 状态管理目录
│ ├── modules/ # 按模块划分的 store
│ └── index.js # store 导出
├── styles/ # 样式文件目录
│ ├── variables.scss # 样式变量
│ ├── mixins.scss # 样式混入
│ └── common.scss # 通用样式
├── utils/ # 工具函数目录
│ ├── request.js # 网络请求工具
│ ├── storage.js # 存储工具
│ └── validator.js # 验证工具
├── App.vue # 应用入口文件
├── main.js # 应用入口文件
├── manifest.json # 应用配置文件
├── pages.json # 页面配置文件
├── uni.scss # 全局样式文件
├── package.json # 项目依赖配置
└── tsconfig.json # TypeScript 配置文件

1.3.3 配置文件详细说明

1. manifest.json

manifest.json 是 uni-app 的应用配置文件,用于配置应用的基本信息、权限、启动画面等:

  • 基础配置:应用名称、版本号、描述、图标等
  • 权限配置:相机、定位、录音等权限
  • 平台配置:各平台的特有配置
  • SDK 配置:地图、支付等 SDK 的配置

示例配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
{
"name": "uni-app 示例",
"appid": "__UNI__XXXXXX",
"versionName": "1.0.0",
"versionCode": "100",
"description": "uni-app 示例应用",
"author": {
"name": "开发者",
"email": "developer@example.com"
},
"permissions": {
"scope.userLocation": {
"desc": "用于获取用户位置信息"
},
"scope.camera": {
"desc": "用于拍照和扫码"
}
},
"mp-weixin": {
"appid": "wxXXXXXXXXXXXX",
"setting": {
"urlCheck": false
},
"usingComponents": true
},
"h5": {
"devServer": {
"port": 8080,
"proxy": {
"/api": {
"target": "https://api.example.com",
"changeOrigin": true,
"pathRewrite": {
"^/api": ""
}
}
}
}
}
}

2. pages.json

pages.json 是 uni-app 的页面配置文件,用于配置页面路由、导航栏、底部 tab 等:

  • pages:配置页面路由和页面样式
  • tabBar:配置底部 tab 栏
  • globalStyle:配置全局样式
  • subPackages:配置分包加载
  • preloadRule:配置页面预加载规则

示例配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
{
"pages": [
{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "首页",
"enablePullDownRefresh": true
}
},
{
"path": "pages/detail/detail",
"style": {
"navigationBarTitleText": "详情页",
"navigationStyle": "custom"
}
}
],
"tabBar": {
"color": "#666666",
"selectedColor": "#007AFF",
"borderStyle": "black",
"backgroundColor": "#FFFFFF",
"list": [
{
"pagePath": "pages/index/index",
"text": "首页",
"iconPath": "static/tabbar/home.png",
"selectedIconPath": "static/tabbar/home-active.png"
},
{
"pagePath": "pages/user/user",
"text": "我的",
"iconPath": "static/tabbar/user.png",
"selectedIconPath": "static/tabbar/user-active.png"
}
]
},
"globalStyle": {
"navigationBarTextStyle": "white",
"navigationBarTitleText": "uni-app 示例",
"navigationBarBackgroundColor": "#007AFF",
"backgroundColor": "#F5F5F5"
},
"subPackages": [
{
"root": "pages/product",
"pages": [
{
"path": "list/list",
"style": {
"navigationBarTitleText": "产品列表"
}
},
{
"path": "detail/detail",
"style": {
"navigationBarTitleText": "产品详情"
}
}
]
}
],
"preloadRule": {
"pages/index/index": {
"network": "all",
"packages": ["pages/product"]
}
}
}

3. uni.scss

uni.scss 是 uni-app 的全局样式文件,用于定义全局样式变量和混合:

  • 颜色变量:主题色、文本色、背景色等
  • 尺寸变量:字体大小、间距、边框等
  • 混合宏:常用的样式混合

示例配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
/* 颜色变量 */
$theme-color: #007AFF;
$text-color: #333333;
$text-color-secondary: #666666;
$text-color-light: #999999;
$background-color: #F5F5F5;
$border-color: #E5E5E5;

/* 尺寸变量 */
$font-size-xs: 24rpx;
$font-size-sm: 28rpx;
$font-size-base: 32rpx;
$font-size-lg: 36rpx;
$font-size-xl: 40rpx;

$spacing-xs: 10rpx;
$spacing-sm: 20rpx;
$spacing-base: 30rpx;
$spacing-lg: 40rpx;
$spacing-xl: 50rpx;

/* 边框半径 */
$border-radius-sm: 4rpx;
$border-radius-base: 8rpx;
$border-radius-lg: 12rpx;
$border-radius-xl: 16rpx;

/* 混合宏 */
@mixin flex-center {
display: flex;
align-items: center;
justify-content: center;
}

@mixin flex-between {
display: flex;
align-items: center;
justify-content: space-between;
}

@mixin text-ellipsis {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}

@mixin text-ellipsis-2 {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
}

1.3.4 模块化开发建议

1. 组件模块化

  • 基础组件:封装通用的 UI 组件,如按钮、输入框、列表等
  • 业务组件:封装特定业务的组件,如商品卡片、订单列表等
  • 页面组件:封装页面级的组件,如首页轮播、个人中心头部等

2. API 模块化

  • 按业务模块划分:将 API 按业务模块划分,如用户、产品、订单等
  • 统一请求封装:封装请求拦截器和响应拦截器
  • 错误处理统一:统一处理 API 错误和异常

3. 状态管理模块化

  • 按业务模块划分:将状态按业务模块划分,如用户状态、产品状态等
  • 模块化命名:使用命名空间避免状态冲突
  • 异步操作封装:将异步操作封装在 actions 中

4. 工具函数模块化

  • 按功能划分:将工具函数按功能划分,如网络、存储、验证等
  • 统一导出:通过 index.js 统一导出工具函数
  • 类型定义:为工具函数添加 TypeScript 类型定义

1.3.5 代码组织最佳实践

1. 页面代码组织

每个页面建议按照以下结构组织代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<template>
<!-- 页面模板 -->
</template>

<script>
// 导入组件、工具函数等
import { mapState, mapActions } from 'vuex';
import MyComponent from '@/components/MyComponent.vue';
import { getUserInfo } from '@/api/user';

export default {
name: 'PageName',
components: {
MyComponent
},
data() {
return {
// 页面数据
};
},
computed: {
...mapState('user', ['userInfo']),
// 计算属性
},
watch: {
// 监听属性
},
created() {
// 页面创建时执行
},
mounted() {
// 页面挂载时执行
},
onLoad(options) {
// 页面加载时执行
},
onShow() {
// 页面显示时执行
},
methods: {
...mapActions('user', ['login']),
// 页面方法
}
};
</script>

<style scoped>
/* 页面样式 */
</style>

2. 组件代码组织

每个组件建议按照以下结构组织代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<template>
<!-- 组件模板 -->
</template>

<script>
export default {
name: 'MyComponent',
props: {
// 组件属性
},
data() {
return {
// 组件数据
};
},
computed: {
// 计算属性
},
watch: {
// 监听属性
},
created() {
// 组件创建时执行
},
mounted() {
// 组件挂载时执行
},
methods: {
// 组件方法
emitEvent() {
this.$emit('eventName', data);
}
}
};
</script>

<style scoped>
/* 组件样式 */
</style>

3. API 代码组织

API 接口建议按照以下结构组织代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// api/user.js
import request from '@/utils/request';

export const getUserInfo = () => {
return request({
url: '/user/info',
method: 'GET'
});
};

export const login = (data) => {
return request({
url: '/user/login',
method: 'POST',
data
});
};

// api/index.js
export * from './user';
export * from './product';
export * from './order';

通过合理的目录结构和代码组织,可以提高项目的可维护性、可扩展性和可读性,为企业级应用开发奠定良好的基础。

2. 核心概念

2.1 页面生命周期

uni-app 的页面生命周期结合了 Vue 的生命周期和小程序的生命周期特点,形成了一套独特的生命周期体系。理解页面生命周期对于开发高质量的 uni-app 应用至关重要。

2.1.1 页面生命周期函数

函数名说明平台差异执行时机
onLoad页面加载时触发,只触发一次所有平台页面创建后,首次显示前
onShow页面显示/切入前台时触发所有平台页面加载后或从后台切入前台时
onReady页面初次渲染完成时触发,只触发一次所有平台页面显示后,首次渲染完成时
onHide页面隐藏/切入后台时触发所有平台页面从前台切入后台时
onUnload页面卸载时触发所有平台页面被关闭或跳转时
onPullDownRefresh下拉刷新时触发所有平台用户下拉页面时
onReachBottom上拉触底时触发所有平台页面滚动到底部时
onShareAppMessage用户点击分享时触发微信小程序、QQ小程序用户点击分享按钮时
onShareTimeline用户点击分享到朋友圈时触发微信小程序用户点击分享到朋友圈按钮时
onAddToFavorites用户点击收藏时触发微信小程序用户点击收藏按钮时
onPageScroll页面滚动时触发所有平台页面滚动时
onResize窗口尺寸变化时触发微信小程序、H5窗口尺寸变化时
onTabItemTap点击 tab 栏时触发所有平台点击 tab 栏时
onNavigationBarButtonTap点击导航栏按钮时触发所有平台点击导航栏按钮时
onBackPress页面返回时触发所有平台页面返回时

2.1.2 生命周期执行顺序

完整的页面生命周期执行顺序

  1. 页面加载阶段

    • beforeCreate(Vue 生命周期)
    • created(Vue 生命周期)
    • onLoad(uni-app 生命周期)
    • onShow(uni-app 生命周期)
    • beforeMount(Vue 生命周期)
    • mounted(Vue 生命周期)
    • onReady(uni-app 生命周期)
  2. 页面交互阶段

    • onPageScroll(页面滚动时)
    • onPullDownRefresh(下拉刷新时)
    • onReachBottom(上拉触底时)
    • onShareAppMessage(分享时)
    • onTabItemTap(点击 tab 时)
  3. 页面隐藏阶段

    • onHide(页面隐藏时)
  4. 页面卸载阶段

    • beforeDestroy(Vue 生命周期)
    • destroyed(Vue 生命周期)
    • onUnload(uni-app 生命周期)

2.1.3 生命周期平台差异

不同平台的生命周期差异

平台差异点
H5支持所有 Vue 生命周期,部分 uni-app 生命周期可能有差异
微信小程序支持所有 uni-app 生命周期,Vue 生命周期正常执行
支付宝小程序部分生命周期可能有延迟,如 onReady 可能晚于 mounted
百度小程序生命周期执行顺序可能与其他平台略有不同
头条小程序部分生命周期可能不支持,如 onShareTimeline
QQ小程序与微信小程序类似,但部分 API 有差异
App支持所有生命周期,性能最优

2.1.4 生命周期最佳实践

1. 数据初始化

  • onLoad:适合进行数据初始化,如获取页面参数、发起网络请求等
  • created:适合进行数据观测、计算属性初始化等

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
onLoad(options) {
// 获取页面参数
const { id } = options;

// 发起网络请求
this.fetchData(id);
},

methods: {
fetchData(id) {
uni.showLoading({ title: '加载中...' });

// 发起网络请求
uni.request({
url: `/api/detail/${id}`,
success: (res) => {
this.detail = res.data;
},
complete: () => {
uni.hideLoading();
}
});
}
}

2. 页面渲染

  • onReady:适合进行 DOM 操作,如获取元素尺寸、初始化第三方库等
  • mounted:适合进行页面初始化操作,如绑定事件监听器等

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
onReady() {
// 获取元素尺寸
const query = uni.createSelectorQuery().in(this);
query.select('.header').boundingClientRect((rect) => {
this.headerHeight = rect.height;
}).exec();

// 初始化第三方库
this.initThirdPartyLib();
},

methods: {
initThirdPartyLib() {
// 初始化第三方库
}
}

3. 页面隐藏与卸载

  • onHide:适合暂停页面活动,如定时器、动画等
  • onUnload:适合清理资源,如定时器、事件监听器、WebSocket 连接等

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
data() {
return {
timer: null
};
},

onShow() {
// 启动定时器
this.timer = setInterval(() => {
this.updateData();
}, 1000);
},

onHide() {
// 暂停定时器
if (this.timer) {
clearInterval(this.timer);
}
},

onUnload() {
// 清理定时器
if (this.timer) {
clearInterval(this.timer);
this.timer = null;
}

// 清理其他资源
this.cleanupResources();
},

methods: {
updateData() {
// 更新数据
},

cleanupResources() {
// 清理其他资源
}
}

4. 下拉刷新与上拉加载

  • onPullDownRefresh:适合刷新页面数据
  • onReachBottom:适合加载更多数据

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
onPullDownRefresh() {
// 刷新数据
this.page = 1;
this.dataList = [];
this.fetchData();
},

onReachBottom() {
// 加载更多数据
if (!this.loading && this.hasMore) {
this.page++;
this.fetchData();
}
},

methods: {
fetchData() {
this.loading = true;

uni.request({
url: '/api/list',
data: {
page: this.page,
limit: 10
},
success: (res) => {
if (this.page === 1) {
this.dataList = res.data.list;
} else {
this.dataList = [...this.dataList, ...res.data.list];
}

this.hasMore = res.data.list.length === 10;
},
complete: () => {
this.loading = false;
uni.stopPullDownRefresh();
}
});
}
}

2.1.5 生命周期与组件生命周期的关系

页面生命周期与组件生命周期的执行顺序

  1. 页面的 beforeCreate
  2. 页面的 created
  3. 页面的 onLoad
  4. 页面的 onShow
  5. 页面的 beforeMount
  6. 组件的 beforeCreate
  7. 组件的 created
  8. 组件的 beforeMount
  9. 组件的 mounted
  10. 页面的 mounted
  11. 页面的 onReady

注意事项

  • 组件的生命周期嵌套在页面的生命周期中执行
  • 父组件的生命周期先于子组件执行
  • 页面的 onReady 会在所有组件 mounted 后执行

2.1.6 生命周期的性能优化

1. 避免在生命周期中执行耗时操作

  • 耗时操作应放在异步函数中执行
  • 避免在 onLoad、onShow 等生命周期中执行大量计算

2. 合理使用缓存

  • 对于不常变化的数据,可使用本地缓存
  • 避免重复发起网络请求

3. 及时清理资源

  • 在 onUnload 中清理定时器、事件监听器等
  • 避免内存泄漏

4. 优化渲染性能

  • 避免在 onPageScroll 中执行频繁的 DOM 操作
  • 使用防抖和节流优化滚动事件

通过合理使用页面生命周期,可以提高应用的性能和用户体验,避免常见的性能问题和内存泄漏。

2.2 组件

2.2.1 内置组件

uni-app 提供了丰富的内置组件,如 view、text、button、image 等,这些组件在各个平台都有良好的兼容性。

常用内置组件

  • view:视图容器,类似于 HTML 的 div
  • text:文本组件
  • button:按钮组件
  • image:图片组件
  • navigator:页面跳转组件
  • scroll-view:滚动视图组件
  • swiper:轮播图组件
  • picker:选择器组件
  • input:输入框组件

2.2.2 自定义组件

创建自定义组件

  1. 在 components 目录下创建组件目录
  2. 创建 .vue 文件,编写组件代码
  3. 在页面中引入并注册组件

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<!-- components/my-component.vue -->
<template>
<view class="my-component">
<text>{{ title }}</text>
</view>
</template>

<script>
export default {
name: 'my-component',
props: {
title: {
type: String,
default: '默认标题'
}
},
data() {
return {};
}
};
</script>

<style scoped>
.my-component {
padding: 20rpx;
background-color: #f5f5f5;
}
</style>

使用组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<template>
<view>
<my-component title="自定义组件" />
</view>
</template>

<script>
import myComponent from '@/components/my-component.vue';

export default {
components: {
myComponent
}
};
</script>

2.3 API

uni-app 封装了各平台的原生 API,提供了统一的调用方式。

2.3.1 常用 API

  • 网络请求:uni.request()
  • 存储:uni.setStorageSync()、uni.getStorageSync()
  • 导航:uni.navigateTo()、uni.redirectTo()、uni.switchTab()
  • 界面:uni.showToast()、uni.showLoading()、uni.showModal()
  • 设备:uni.getSystemInfoSync()
  • 媒体:uni.chooseImage()、uni.uploadFile()

2.3.2 API 调用示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 网络请求
uni.request({
url: 'https://api.example.com/data',
method: 'GET',
success: (res) => {
console.log(res.data);
},
fail: (err) => {
console.error(err);
}
});

// 存储数据
uni.setStorageSync('userInfo', { name: '张三', age: 20 });

// 获取存储数据
const userInfo = uni.getStorageSync('userInfo');

// 页面跳转
uni.navigateTo({
url: '/pages/detail/detail?id=1'
});

2.4 路由与页面跳转

2.4.1 路由配置

在 pages.json 中配置页面路由:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
{
"pages": [
{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "首页"
}
},
{
"path": "pages/detail/detail",
"style": {
"navigationBarTitleText": "详情页"
}
}
],
"tabBar": {
"list": [
{
"pagePath": "pages/index/index",
"text": "首页",
"iconPath": "static/home.png",
"selectedIconPath": "static/home-active.png"
},
{
"pagePath": "pages/mine/mine",
"text": "我的",
"iconPath": "static/mine.png",
"selectedIconPath": "static/mine-active.png"
}
]
}
}

2.4.2 页面跳转方式

  • uni.navigateTo():保留当前页面,跳转到应用内的某个页面
  • uni.redirectTo():关闭当前页面,跳转到应用内的某个页面
  • uni.reLaunch():关闭所有页面,打开到应用内的某个页面
  • uni.switchTab():跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面
  • uni.navigateBack():关闭当前页面,返回上一页面或多级页面

3. 组件与 UI

3.1 内置 UI 组件

3.1.1 uni-ui

uni-ui 是 DCloud 官方提供的一套 UI 组件库,适配多端,风格统一。

安装
在 HBuilderX 中点击「工具」→「插件安装」→ 搜索「uni-ui」并安装。

使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<template>
<view>
<uni-badge text="12" type="error"></uni-badge>
<uni-button type="primary">按钮</uni-button>
</view>
</template>

<script>
import { uniBadge, uniButton } from '@dcloudio/uni-ui';

export default {
components: {
uniBadge,
uniButton
}
};
</script>

3.1.2 其他 UI 库

  • uView UI:基于 uni-app 的 UI 框架
  • ColorUI:鲜亮的高饱和色彩,专注视觉的小程序组件库
  • ThorUI:轻量级高性能 UI 组件库

3.2 自定义组件开发

3.2.1 组件通信

  • props/emit:父组件向子组件传递数据,子组件向父组件传递事件
  • $refs:父组件通过 ref 访问子组件实例
  • globalData:全局数据
  • Vuex:状态管理

3.2.2 组件生命周期

组件的生命周期与页面生命周期类似,但也有一些差异:

  • beforeCreate:组件实例创建前
  • created:组件实例创建后
  • beforeMount:组件挂载前
  • mounted:组件挂载后
  • beforeUpdate:组件更新前
  • updated:组件更新后
  • beforeDestroy:组件销毁前
  • destroyed:组件销毁后

3.3 组件封装最佳实践

  • 单一职责:一个组件只负责一个功能
  • 可配置性:通过 props 提供配置项
  • 事件传递:通过 emit 传递事件
  • 样式隔离:使用 scoped 或 CSS Modules
  • 文档完善:提供清晰的使用文档

4. 状态管理

4.1 Vuex

uni-app 内置了 Vuex,可以直接使用。

4.1.1 创建 store

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// store/index.js
import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

export default new Vuex.Store({
state: {
userInfo: null,
token: ''
},
mutations: {
setUserInfo(state, userInfo) {
state.userInfo = userInfo;
},
setToken(state, token) {
state.token = token;
}
},
actions: {
login({ commit }, userInfo) {
// 模拟登录请求
return new Promise((resolve) => {
setTimeout(() => {
commit('setUserInfo', userInfo);
commit('setToken', 'mock-token');
resolve();
}, 1000);
});
}
},
getters: {
isLoggedIn: state => !!state.token
}
});

4.1.2 在 main.js 中引入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// main.js
import Vue from 'vue';
import App from './App.vue';
import store from './store';

Vue.config.productionTip = false;

App.mpType = 'app';

const app = new Vue({
...App,
store
});
app.$mount();

4.1.3 在组件中使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<template>
<view>
<text v-if="isLoggedIn">{{ userInfo.name }}</text>
<button v-else @click="login">登录</button>
</view>
</template>

<script>
import { mapState, mapGetters, mapActions } from 'vuex';

export default {
computed: {
...mapState(['userInfo']),
...mapGetters(['isLoggedIn'])
},
methods: {
...mapActions(['login']),
handleLogin() {
this.login({ name: '张三', age: 20 });
}
}
};
</script>

4.2 Pinia

Pinia 是 Vue 3 推荐的状态管理库,也可以在 uni-app 中使用。

4.2.1 安装 Pinia

1
npm install pinia

4.2.2 创建 store

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// store/user.js
import { defineStore } from 'pinia';

export const useUserStore = defineStore('user', {
state: () => ({
userInfo: null,
token: ''
}),
getters: {
isLoggedIn: (state) => !!state.token
},
actions: {
login(userInfo) {
// 模拟登录请求
return new Promise((resolve) => {
setTimeout(() => {
this.userInfo = userInfo;
this.token = 'mock-token';
resolve();
}, 1000);
});
}
}
});

4.2.3 在 main.js 中引入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// main.js
import Vue from 'vue';
import App from './App.vue';
import { createPinia, PiniaVuePlugin } from 'pinia';

Vue.use(PiniaVuePlugin);
const pinia = createPinia();

Vue.config.productionTip = false;

App.mpType = 'app';

const app = new Vue({
...App,
pinia
});
app.$mount();

4.2.4 在组件中使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<template>
<view>
<text v-if="userStore.isLoggedIn">{{ userStore.userInfo.name }}</text>
<button v-else @click="handleLogin">登录</button>
</view>
</template>

<script>
import { useUserStore } from '@/store/user';

export default {
data() {
return {
userStore: useUserStore()
};
},
methods: {
handleLogin() {
this.userStore.login({ name: '张三', age: 20 });
}
}
};
</script>

5. 网络请求

5.1 基础网络请求

5.1.1 使用 uni.request

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
uni.request({
url: 'https://api.example.com/data',
method: 'GET',
header: {
'Content-Type': 'application/json'
},
data: {
page: 1,
limit: 10
},
success: (res) => {
console.log(res.data);
},
fail: (err) => {
console.error(err);
}
});

5.2 封装请求工具

5.2.1 创建 request.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
// utils/request.js

const baseURL = 'https://api.example.com';

// 请求拦截器
const requestInterceptor = (config) => {
// 添加 token
const token = uni.getStorageSync('token');
if (token) {
config.header.Authorization = `Bearer ${token}`;
}
return config;
};

// 响应拦截器
const responseInterceptor = (response) => {
if (response.statusCode === 200) {
return response.data;
} else {
uni.showToast({
title: '请求失败',
icon: 'none'
});
return Promise.reject(response);
}
};

// 封装请求方法
const request = (options) => {
options.url = baseURL + options.url;
options = requestInterceptor(options);

return new Promise((resolve, reject) => {
uni.request({
...options,
success: (res) => {
const result = responseInterceptor(res);
resolve(result);
},
fail: (err) => {
reject(err);
}
});
});
};

// 封装 GET 请求
export const get = (url, params) => {
return request({
url,
method: 'GET',
data: params
});
};

// 封装 POST 请求
export const post = (url, data) => {
return request({
url,
method: 'POST',
data
});
};

export default request;

5.2.2 使用封装的请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import { get, post } from '@/utils/request';

// GET 请求
get('/user/list', { page: 1, limit: 10 })
.then((res) => {
console.log(res);
})
.catch((err) => {
console.error(err);
});

// POST 请求
post('/user/login', { username: 'admin', password: '123456' })
.then((res) => {
console.log(res);
})
.catch((err) => {
console.error(err);
});

5.3 跨域问题

5.3.1 开发环境跨域

在 HBuilderX 中,可以在 manifest.json 中配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
"h5": {
"devServer": {
"proxy": {
"/api": {
"target": "https://api.example.com",
"changeOrigin": true,
"pathRewrite": {
"^/api": ""
}
}
}
}
}
}

5.3.2 生产环境跨域

生产环境需要在服务器端配置 CORS:

1
2
3
4
5
6
7
8
9
location / {
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods 'GET, POST, PUT, DELETE, OPTIONS';
add_header Access-Control-Allow-Headers 'Content-Type, Authorization';

if ($request_method = 'OPTIONS') {
return 204;
}
}

6. 跨平台适配

6.1 平台差异

uni-app 虽然支持多端运行,但不同平台之间仍然存在一些差异。

6.1.1 平台差异表

功能H5微信小程序支付宝小程序百度小程序头条小程序QQ小程序
支付支持支持支持支持支持支持
分享支持支持支持支持支持支持
地图支持支持支持支持支持支持
扫码支持支持支持支持支持支持
推送不支持支持支持支持支持支持

6.2 条件编译

使用条件编译可以针对不同平台编写不同的代码。

6.2.1 条件编译语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<template>
<view>
<!-- #ifdef H5 -->
<view>这是 H5 平台的内容</view>
<!-- #endif -->

<!-- #ifdef MP-WEIXIN -->
<view>这是微信小程序平台的内容</view>
<!-- #endif -->

<!-- #ifdef APP-PLUS -->
<view>这是 App 平台的内容</view>
<!-- #endif -->
</view>
</template>

<script>
export default {
mounted() {
// #ifdef H5
console.log('H5 平台');
// #endif

// #ifdef MP-WEIXIN
console.log('微信小程序平台');
// #endif
}
};
</script>

<style>
/* #ifdef H5 */
view {
font-size: 16px;
}
/* #endif */

/* #ifdef MP-WEIXIN */
view {
font-size: 32rpx;
}
/* #endif */
</style>

6.2.2 平台标识

平台标识
H5H5
微信小程序MP-WEIXIN
支付宝小程序MP-ALIPAY
百度小程序MP-BAIDU
头条小程序MP-TOUTIAO
QQ小程序MP-QQ
钉钉小程序MP-DINGTALK
淘宝小程序MP-TAOBAO
AppAPP-PLUS
App-nvueAPP-NVUE
快应用QUICKAPP-WEBVIEW

6.3 适配方案

6.3.1 尺寸适配

  • 使用 rpx 单位:rpx 是相对单位,1rpx = 屏幕宽度/750
  • 避免使用 px 单位:px 是绝对单位,在不同屏幕尺寸下显示效果不同
  • 使用 flex 布局:flex 布局可以自适应不同屏幕尺寸

6.3.2 样式适配

  • 使用 uni.scss 中的全局变量
  • 使用条件编译针对不同平台编写不同的样式
  • 使用 CSS 变量实现主题切换

6.3.3 API 适配

  • 使用 uni-app 封装的统一 API
  • 对于平台特有的 API,使用条件编译
  • 封装平台差异,提供统一的调用接口

7. 性能优化

7.1 页面性能优化

7.1.1 渲染性能

  • 减少节点数量:避免嵌套层级过深
  • 使用虚拟列表:对于长列表,使用虚拟列表减少 DOM 节点
  • 避免频繁更新:使用防抖、节流减少频繁更新
  • 使用分包加载:减小主包体积,提高加载速度

7.1.2 启动性能

  • 减少主包体积:将不常用的页面放入分包
  • 预加载:使用 uni.preloadPage() 预加载页面
  • 骨架屏:使用骨架屏提升用户体验
  • 懒加载:图片、组件懒加载

7.2 网络性能优化

7.2.1 请求优化

  • 合并请求:减少 HTTP 请求次数
  • 缓存策略:使用本地缓存减少重复请求
  • 压缩数据:使用 gzip 压缩数据
  • CDN 加速:使用 CDN 加速静态资源

7.2.2 图片优化

  • 图片压缩:使用压缩后的图片
  • 图片格式:使用 WebP 格式图片
  • 图片懒加载:使用 uni.createIntersectionObserver() 实现图片懒加载
  • 占位符:使用占位符提升用户体验

7.3 代码优化

7.3.1 代码分割

  • 分包加载:将应用分为主包和分包
  • 按需加载:使用动态导入按需加载组件

7.3.2 内存优化

  • 及时销毁:组件销毁时清理定时器、事件监听器
  • 减少全局变量:避免使用过多的全局变量
  • 合理使用闭包:避免内存泄漏

8. 企业级应用开发

8.1 项目架构

8.1.1 目录结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
├── api/             # API 接口
├── components/ # 组件
├── pages/ # 页面
├── static/ # 静态资源
├── store/ # 状态管理
├── utils/ # 工具函数
├── services/ # 服务层
├── middlewares/ # 中间件
├── filters/ # 过滤器
├── mixins/ # 混入
├── App.vue # 应用入口
├── main.js # 应用入口
├── manifest.json # 应用配置
├── pages.json # 页面配置
└── uni.scss # 全局样式

8.1.2 分层架构

  • API 层:封装接口调用
  • Service 层:封装业务逻辑
  • Store 层:状态管理
  • Component 层:UI 组件
  • Page 层:页面

8.2 开发规范

8.2.1 命名规范

  • 文件命名:使用小写字母,单词之间用连字符连接
  • 组件命名:使用 PascalCase 命名法
  • 变量命名:使用 camelCase 命名法
  • 常量命名:使用 UPPER_SNAKE_CASE 命名法
  • 函数命名:使用 camelCase 命名法

8.2.2 代码规范

  • 缩进:使用 2 个空格
  • 分号:使用分号结束语句
  • 引号:使用单引号
  • 括号:使用大括号包裹代码块
  • 注释:使用 JSDoc 注释

8.3 版本控制

8.3.1 Git 规范

  • 分支管理

    • master:主分支
    • develop:开发分支
    • feature:功能分支
    • hotfix:修复分支
  • 提交规范

    • feat:新增功能
    • fix:修复 bug
    • docs:文档更新
    • style:代码风格调整
    • refactor:代码重构
    • test:测试代码
    • chore:构建工具或依赖更新

8.4 部署与发布

8.4.1 构建流程

  1. 代码检查:使用 ESLint 检查代码
  2. 单元测试:运行单元测试
  3. 构建:使用 HBuilderX 或命令行构建
  4. 部署:部署到服务器或发布到应用商店

8.4.2 发布平台

  • H5:部署到 Web 服务器
  • 微信小程序:发布到微信小程序平台
  • 支付宝小程序:发布到支付宝小程序平台
  • 百度小程序:发布到百度小程序平台
  • 头条小程序:发布到头条小程序平台
  • QQ小程序:发布到 QQ 小程序平台
  • App:发布到应用商店

8.5 监控与错误处理

8.5.1 错误监控

  • try/catch:捕获同步错误
  • Promise.catch:捕获异步错误
  • 全局错误处理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// main.js
Vue.config.errorHandler = (err, vm, info) => {
console.error('Vue 错误:', err);
console.error('错误信息:', info);
// 上报错误
};

// 监听 unhandledrejection 事件
window.addEventListener('unhandledrejection', (event) => {
console.error('未处理的 Promise 错误:', event.reason);
// 上报错误
});

// 监听 error 事件
window.addEventListener('error', (event) => {
console.error('全局错误:', event.error);
// 上报错误
});

8.5.2 性能监控

  • 首屏加载时间
1
2
3
4
5
6
7
8
9
// 记录开始时间
const startTime = Date.now();

// 监听页面加载完成
window.addEventListener('load', () => {
const loadTime = Date.now() - startTime;
console.log('首屏加载时间:', loadTime);
// 上报性能数据
});
  • 页面切换时间
1
2
3
4
5
6
7
8
9
10
11
// 监听页面显示
uni.onPageShow((res) => {
const pageStartTime = Date.now();

// 监听页面初次渲染完成
uni.onPageReady((res) => {
const renderTime = Date.now() - pageStartTime;
console.log('页面渲染时间:', renderTime);
// 上报性能数据
});
});

9. 实战案例

9.1 电商应用

9.1.1 功能模块

  • 首页:轮播图、分类导航、推荐商品
  • 商品列表:商品展示、筛选、排序
  • 商品详情:商品信息、规格选择、加入购物车
  • 购物车:商品管理、数量修改、结算
  • 订单:订单列表、订单详情、订单状态
  • 个人中心:用户信息、收货地址、订单管理

9.1.2 技术实现

  • 状态管理:使用 Vuex 管理全局状态
  • 网络请求:封装 request 工具
  • UI 组件:使用 uni-ui 组件库
  • 支付:集成各平台支付
  • 分享:集成各平台分享

9.2 企业管理系统

9.2.1 功能模块

  • 登录:账号密码登录、验证码登录
  • 首页:数据看板、快捷入口
  • 用户管理:用户列表、用户详情、添加/编辑用户
  • 角色管理:角色列表、权限配置
  • 权限管理:菜单权限、按钮权限
  • 数据统计:数据图表、报表导出

9.2.2 技术实现

  • 权限控制:基于角色的权限控制
  • 数据可视化:使用 echarts 实现数据图表
  • 表单验证:使用 async-validator 进行表单验证
  • 导出功能:使用 xlsx 库实现 Excel 导出
  • WebSocket:实时数据推送

10. 总结与展望

10.1 uni-app 的优势

  • 开发效率高:一套代码多端运行
  • 性能优异:底层使用原生渲染
  • 生态丰富:大量的 UI 组件和插件
  • 学习成本低:使用 Vue.js 语法
  • 跨平台能力强:支持 10+ 个平台

10.2 uni-app 的局限性

  • 平台差异:不同平台之间存在差异
  • 原生能力:部分原生能力需要使用插件
  • 性能优化:需要针对不同平台进行优化

10.3 未来发展

  • Vue 3 支持:全面支持 Vue 3
  • 更多平台:支持更多的平台
  • 更好的性能:进一步提升性能
  • 更丰富的生态:完善生态系统

10.4 学习建议

  • 掌握基础知识:Vue.js、JavaScript、CSS
  • 实践项目:通过实际项目巩固知识
  • 关注官方文档:及时了解最新特性
  • 社区交流:参与社区讨论,分享经验
  • 持续学习:关注前端技术发展趋势

附录

常用 API 参考

API说明平台支持
uni.request网络请求所有平台
uni.setStorageSync存储数据所有平台
uni.getStorageSync获取存储数据所有平台
uni.navigateTo页面跳转所有平台
uni.showToast显示提示信息所有平台
uni.showLoading显示加载动画所有平台
uni.hideLoading隐藏加载动画所有平台
uni.showModal显示模态框所有平台
uni.chooseImage选择图片所有平台
uni.uploadFile上传文件所有平台
uni.downloadFile下载文件所有平台
uni.getSystemInfoSync获取系统信息所有平台
uni.getLocation获取位置信息所有平台
uni.makePhoneCall拨打电话所有平台

常见问题与解决方案

Q: 跨域问题如何解决?
A: 在开发环境中,在 manifest.json 中配置 devServer.proxy;在生产环境中,在服务器端配置 CORS。

Q: 如何优化首屏加载速度?
A: 减少主包体积、使用分包加载、预加载页面、使用骨架屏、图片懒加载。

Q: 如何处理平台差异?
A: 使用条件编译、封装平台差异、参考官方文档的平台差异说明。

Q: 如何实现图片懒加载?
A: 使用 uni.createIntersectionObserver() 实现图片懒加载。

Q: 如何实现自定义导航栏?
A: 在 pages.json 中设置 navigationStyle: ‘custom’,然后自定义导航栏组件。

Q: 如何实现下拉刷新和上拉加载?
A: 在 pages.json 中配置 enablePullDownRefresh: true,然后在页面中实现 onPullDownRefresh 和 onReachBottom 方法。

Q: 如何实现全局状态管理?
A: 使用 Vuex 或 Pinia 实现全局状态管理。

Q: 如何实现路由拦截?
A: 使用 uni.addInterceptor() 实现路由拦截。

Q: 如何实现支付功能?
A: 使用 uni.requestPayment() 实现支付功能,注意不同平台的参数差异。

Q: 如何实现分享功能?
A: 在页面中实现 onShareAppMessage 方法,注意不同平台的参数差异。

资源推荐

开发工具

结语

uni-app 作为一个跨平台开发框架,为开发者提供了一种高效、便捷的开发方式。通过学习本读书笔记,你应该已经掌握了 uni-app 的核心概念、开发技巧和最佳实践。

在实际开发中,你需要根据具体项目的需求,灵活运用这些知识,同时关注官方文档的更新,及时了解新特性和最佳实践。

最后,希望你在 uni-app 开发的道路上越走越远,开发出更多优秀的跨平台应用!