《uni-app 跨端开发完整指南:从基础入门到 H5、小程序、App 发布上线》

uni-app 详细讲解:从入门、三端适配到 H5 / 小程序 / App 发布上线

适合对象:有 HTML、CSS、JavaScript、Vue 基础,想用一套代码开发 H5、小程序、App 的前端开发者。

推荐技术栈:uni-app + Vue3 + TypeScript + Vite + Pinia + SCSS + uni-ui/uView Plus

更新时间:2026 年


目录

  1. [uni-app 是什么](#uni-app 是什么)
  2. [uni-app 适合做什么项目](#uni-app 适合做什么项目)
  3. [uni-app 技术栈推荐](#uni-app 技术栈推荐)
  4. 开发环境准备
  5. [创建 uni-app 项目](#创建 uni-app 项目)
  6. 项目目录结构详细讲解
  7. [核心配置文件 pages.json 详细讲解](#核心配置文件 pages.json 详细讲解)
  8. [核心配置文件 manifest.json 详细讲解](#核心配置文件 manifest.json 详细讲解)
  9. [package.json、vite.config.ts 和环境变量](#package.json、vite.config.ts 和环境变量)
  10. 页面、组件和基础语法
  11. 路由跳转和登录拦截
  12. 网络请求封装
  13. 本地缓存封装
  14. [Pinia 状态管理](#Pinia 状态管理)
  15. 生命周期详细讲解
  16. [样式、rpx、flex 和安全区适配](#样式、rpx、flex 和安全区适配)
  17. 条件编译详细讲解
  18. [一套代码如何适配 H5、小程序、App 三端](#一套代码如何适配 H5、小程序、App 三端)
  19. [H5 发布流程和配置](#H5 发布流程和配置)
  20. 微信小程序发布流程和配置
  21. [App 发布流程和配置](#App 发布流程和配置)
  22. 三端发布命令和产物目录
  23. 项目实战:登录、首页、列表、详情、个人中心
  24. 常见问题和解决方案
  25. 学习路线
  26. 资源文档链接大全
  27. 上线前检查清单

1. uni-app 是什么?

uni-app 是 DCloud 推出的跨端应用开发框架。它的核心目标是:

使用 Vue 语法开发,一套代码发布到多个平台。

常见可发布平台包括:

  • H5 / Web
  • Android App
  • iOS App
  • 微信小程序
  • 支付宝小程序
  • 抖音小程序
  • 百度小程序
  • QQ 小程序
  • 快手小程序
  • 钉钉小程序
  • 飞书小程序
  • 小红书小程序
  • 鸿蒙相关平台,具体能力以官方当前文档为准

简单理解:

txt 复制代码
Vue 语法
+ uni-app 内置组件
+ uni-app API
+ pages.json 路由配置
+ manifest.json 平台配置
+ 条件编译
= 一套代码多端发布

2. uni-app 适合做什么项目?

2.1 非常适合

项目类型 适合程度 说明
企业官网 H5 可以快速适配移动端
微信小程序 uni-app 对小程序生态支持成熟
多端小程序 同一业务可以发布到微信、支付宝、抖音等
商城系统 商品、购物车、订单、个人中心都很适合
预约系统 医疗预约、课程预约、门店预约
社区资讯类 App 列表、详情、评论、分享场景常见
企业内部移动端 审批、报表、移动办公
活动页 / 营销页 中高 H5 和小程序都可以做
轻量 App 中高 不依赖过多复杂原生能力时很适合

2.2 不太适合

项目类型 原因
大型 3D 游戏 图形渲染和性能要求高
重度音视频剪辑 App 强依赖原生能力和高性能处理
极复杂原生交互 App 需要大量原生插件和平台差异处理
高频实时交易类系统 对稳定性、性能、网络链路要求极高
复杂地图导航类 App 原生地图 SDK 能力差异较多

3. uni-app 技术栈推荐

3.1 现代推荐栈

txt 复制代码
uni-app
Vue3
TypeScript
Vite
Pinia
SCSS
uni-ui / uView Plus
HBuilderX / VS Code
微信开发者工具

3.2 每个技术的作用

技术 作用
uni-app 跨端框架核心
Vue3 页面、组件、响应式开发
TypeScript 类型约束,减少运行时报错
Vite 构建工具,开发启动快
Pinia 全局状态管理
SCSS 样式变量、嵌套、mixin
uni-ui DCloud 官方 UI 组件库
uView Plus 常用第三方移动端 UI 组件库
pages.json 页面路由、导航栏、tabBar 配置
manifest.json 应用名称、图标、权限、平台发行配置
HBuilderX uni-app 官方推荐开发工具,打包 App 更方便
微信开发者工具 微信小程序调试和上传必备

4. 开发环境准备

4.1 必装工具

工具 用途 下载地址
HBuilderX 创建、运行、发行 uni-app 项目 https://www.dcloud.io/hbuilderx.html
Node.js CLI 项目、npm 包管理 https://nodejs.org/
微信开发者工具 微信小程序预览、上传、审核前测试 https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html
VS Code 可选代码编辑器 https://code.visualstudio.com/
Git 代码版本管理 https://git-scm.com/

4.2 推荐插件

插件 作用
Vue - Official Vue 语法支持
TypeScript Vue Plugin Vue TS 辅助
ESLint 代码规范
Prettier 代码格式化
uni-app snippets uni-app 代码片段
SCSS IntelliSense SCSS 辅助

5. 创建 uni-app 项目

uni-app 项目主要有两种创建方式:

  1. HBuilderX 可视化创建
  2. CLI 命令行创建

5.1 HBuilderX 创建项目

适合新手和 App 打包场景。

步骤:

txt 复制代码
打开 HBuilderX
→ 文件
→ 新建
→ 项目
→ 选择 uni-app
→ 输入项目名称
→ 选择 Vue3 / Vue2 模板
→ 创建

优点:

  • 创建简单
  • 内置 uni-app 编译器
  • App 真机运行、云打包方便
  • pages.json、manifest.json 有可视化配置
  • 对新手友好

缺点:

  • 工程化自由度略低
  • 团队协作时需要统一 HBuilderX 版本
  • 对熟悉 VS Code + CLI 的开发者不够灵活

5.2 CLI 创建项目

适合前端工程化开发者。

bash 复制代码
npx degit dcloudio/uni-preset-vue#vite-ts my-uniapp-project

cd my-uniapp-project

npm install

npm run dev:h5

常用命令:

bash 复制代码
# 运行到 H5
npm run dev:h5

# 打包 H5
npm run build:h5

# 运行到微信小程序
npm run dev:mp-weixin

# 打包微信小程序
npm run build:mp-weixin

# 运行到 App
npm run dev:app

# 打包 App 资源
npm run build:app

5.3 HBuilderX 项目和 CLI 项目区别

对比项 HBuilderX 项目 CLI 项目
创建方式 图形化 命令行
编译器位置 HBuilderX 内置 项目 node_modules
代码目录 根目录 通常在 src 目录
打包产物 unpackage 目录 dist 目录
App 云打包 更方便 仍建议拖入 HBuilderX
团队工程化 一般 更强
适合人群 新手、App 开发 熟悉前端工程化开发者

6. 项目目录结构详细讲解

推荐企业级目录:

txt 复制代码
src
├─ api                       # 接口请求模块
│  ├─ user.ts
│  ├─ home.ts
│  ├─ order.ts
│  └─ upload.ts
├─ components                # 公共组件
│  ├─ BaseNavbar
│  │  └─ BaseNavbar.vue
│  └─ GoodsCard
│     └─ GoodsCard.vue
├─ hooks                     # 组合式函数
│  ├─ useLogin.ts
│  ├─ usePaging.ts
│  └─ useSystemInfo.ts
├─ pages                     # 页面目录
│  ├─ index
│  │  └─ index.vue
│  ├─ login
│  │  └─ login.vue
│  ├─ goods
│  │  └─ detail.vue
│  └─ user
│     └─ user.vue
├─ pages-sub                 # 分包页面
│  ├─ order
│  │  └─ list.vue
│  └─ settings
│     └─ index.vue
├─ platform                  # 平台差异封装
│  ├─ login.ts
│  ├─ pay.ts
│  ├─ share.ts
│  └─ permission.ts
├─ static                    # 静态资源
│  ├─ logo.png
│  └─ tabbar
├─ stores                    # Pinia 状态管理
│  ├─ user.ts
│  └─ app.ts
├─ styles                    # 全局样式
│  ├─ variables.scss
│  ├─ mixins.scss
│  └─ common.scss
├─ types                     # TS 类型声明
│  ├─ user.d.ts
│  └─ api.d.ts
├─ utils                     # 工具函数
│  ├─ request.ts
│  ├─ router.ts
│  ├─ storage.ts
│  ├─ env.ts
│  └─ validate.ts
├─ App.vue                   # 应用入口
├─ main.ts                   # Vue 初始化入口
├─ pages.json                # 页面路由和窗口配置
├─ manifest.json             # 应用和平台配置
├─ uni.scss                  # 全局 SCSS 变量
└─ vite.config.ts            # Vite 配置

6.1 目录职责说明

目录/文件 职责
pages 主包页面,首页、登录、个人中心等
pages-sub 分包页面,用于小程序减小主包体积
components 可复用组件
api 所有接口函数
utils/request.ts 请求封装、token、错误处理
utils/router.ts 路由跳转封装、登录拦截
utils/storage.ts 缓存封装
stores 用户信息、token、全局配置
platform 微信、H5、App 特有能力封装
styles 全局样式变量和 mixin
static 图片、字体、tabBar 图标
pages.json 页面注册、导航栏、tabBar、分包
manifest.json 应用名称、图标、权限、AppID、发行配置

7. 核心配置文件 pages.json 详细讲解

pages.json 是 uni-app 最重要的配置文件之一,用来配置:

  • 页面路径
  • 页面标题
  • 导航栏样式
  • 全局窗口样式
  • tabBar
  • 分包
  • easycom 组件自动导入
  • H5 大屏窗口
  • 页面启动模式

7.1 基础 pages.json 示例

json 复制代码
{
  "pages": [
    {
      "path": "pages/index/index",
      "style": {
        "navigationBarTitleText": "首页"
      }
    },
    {
      "path": "pages/category/index",
      "style": {
        "navigationBarTitleText": "分类"
      }
    },
    {
      "path": "pages/user/index",
      "style": {
        "navigationBarTitleText": "我的"
      }
    },
    {
      "path": "pages/login/index",
      "style": {
        "navigationBarTitleText": "登录"
      }
    }
  ],
  "globalStyle": {
    "navigationBarTextStyle": "black",
    "navigationBarTitleText": "uni-app 项目",
    "navigationBarBackgroundColor": "#ffffff",
    "backgroundColor": "#f5f5f5",
    "enablePullDownRefresh": false,
    "onReachBottomDistance": 80
  }
}

7.2 pages 配置

pages 用于注册页面。

json 复制代码
{
  "path": "pages/index/index",
  "style": {
    "navigationBarTitleText": "首页"
  }
}

注意:

txt 复制代码
1. pages 数组第一个页面默认是启动首页。
2. path 不要以 / 开头。
3. 每个页面必须在 pages.json 中注册后才能跳转。
4. tabBar 页面也必须在 pages 中注册。

7.3 globalStyle 全局窗口配置

json 复制代码
{
  "globalStyle": {
    "navigationBarTextStyle": "black",
    "navigationBarTitleText": "商城系统",
    "navigationBarBackgroundColor": "#ffffff",
    "backgroundColor": "#f7f8fa",
    "enablePullDownRefresh": false,
    "onReachBottomDistance": 80
  }
}

常用属性:

属性 说明
navigationBarTextStyle 导航栏文字颜色,只支持 blackwhite
navigationBarTitleText 默认导航栏标题
navigationBarBackgroundColor 导航栏背景色
backgroundColor 页面背景色
enablePullDownRefresh 是否开启下拉刷新
onReachBottomDistance 页面触底距离

7.4 单页面 style 配置

json 复制代码
{
  "path": "pages/goods/detail",
  "style": {
    "navigationBarTitleText": "商品详情",
    "enablePullDownRefresh": true,
    "navigationBarBackgroundColor": "#ffffff",
    "backgroundColor": "#f5f5f5"
  }
}

单页面配置会覆盖全局配置。

7.5 tabBar 配置

json 复制代码
{
  "tabBar": {
    "color": "#666666",
    "selectedColor": "#1677ff",
    "backgroundColor": "#ffffff",
    "borderStyle": "black",
    "list": [
      {
        "pagePath": "pages/index/index",
        "iconPath": "static/tabbar/home.png",
        "selectedIconPath": "static/tabbar/home-active.png",
        "text": "首页"
      },
      {
        "pagePath": "pages/category/index",
        "iconPath": "static/tabbar/category.png",
        "selectedIconPath": "static/tabbar/category-active.png",
        "text": "分类"
      },
      {
        "pagePath": "pages/user/index",
        "iconPath": "static/tabbar/user.png",
        "selectedIconPath": "static/tabbar/user-active.png",
        "text": "我的"
      }
    ]
  }
}

注意:

txt 复制代码
1. tabBar 页面跳转必须使用 uni.switchTab。
2. 非 tabBar 页面跳转通常使用 uni.navigateTo。
3. tabBar 图标建议放 static 目录。
4. 小程序 tabBar 图标大小和格式要注意,建议 PNG。

7.6 分包 subPackages

分包主要用于小程序,解决主包体积限制问题。

json 复制代码
{
  "subPackages": [
    {
      "root": "pages-sub/order",
      "pages": [
        {
          "path": "list",
          "style": {
            "navigationBarTitleText": "订单列表"
          }
        },
        {
          "path": "detail",
          "style": {
            "navigationBarTitleText": "订单详情"
          }
        }
      ]
    },
    {
      "root": "pages-sub/settings",
      "pages": [
        {
          "path": "index",
          "style": {
            "navigationBarTitleText": "设置"
          }
        }
      ]
    }
  ]
}

跳转分包页面:

ts 复制代码
uni.navigateTo({
  url: '/pages-sub/order/detail?id=100'
})

分包建议:

txt 复制代码
主包:登录、首页、tabBar 页面、公共组件、核心工具
分包:订单、设置、活动、详情、非首屏功能

7.7 easycom 自动导入组件

json 复制代码
{
  "easycom": {
    "autoscan": true,
    "custom": {
      "^base-(.*)": "@/components/base-$1/base-$1.vue",
      "^u-(.*)": "uview-plus/components/u-$1/u-$1.vue"
    }
  }
}

符合以下目录结构的组件可以自动导入:

txt 复制代码
components/GoodsCard/GoodsCard.vue
components/base-button/base-button.vue
uni_modules/uni-card/components/uni-card/uni-card.vue

页面中可以直接使用:

vue 复制代码
<template>
  <GoodsCard />
  <base-button>提交</base-button>
  <uni-card title="标题">内容</uni-card>
</template>

8. 核心配置文件 manifest.json 详细讲解

manifest.json 是应用级配置文件,主要配置:

  • 应用名称
  • AppID
  • 版本号
  • 图标
  • 启动图
  • 权限
  • H5 配置
  • 小程序配置
  • App 配置
  • SDK 配置
  • 网络超时时间
  • 原生模块

8.1 基础字段

json 复制代码
{
  "name": "uniapp-shop",
  "appid": "__UNI__XXXXXXX",
  "description": "uni-app 商城项目",
  "versionName": "1.0.0",
  "versionCode": 100,
  "locale": "zh-Hans"
}
字段 说明
name 应用名称
appid DCloud 应用标识
description 应用描述
versionName 版本名称,例如 1.0.0
versionCode 版本号,例如 100
locale 默认语言

版本建议:

txt 复制代码
versionName:给用户看的版本,如 1.0.0、1.1.0
versionCode:给应用市场识别升级用,每次发布必须递增,如 100、101、102

8.2 networkTimeout 网络超时配置

json 复制代码
{
  "networkTimeout": {
    "request": 60000,
    "connectSocket": 60000,
    "uploadFile": 60000,
    "downloadFile": 60000
  }
}

建议:

场景 建议超时
普通请求 10000 - 30000 ms
上传图片 60000 ms
上传视频 120000 ms
弱网场景 适当放宽并做重试

8.3 H5 配置

json 复制代码
{
  "h5": {
    "title": "uni-app 商城",
    "router": {
      "mode": "hash",
      "base": "/"
    },
    "devServer": {
      "port": 5173,
      "proxy": {
        "/api": {
          "target": "https://api.example.com",
          "changeOrigin": true,
          "secure": false
        }
      }
    }
  }
}

常用说明:

配置 作用
title 浏览器标题
router.mode 路由模式,常用 hashhistory
router.base 部署基础路径
devServer.port 本地开发端口
devServer.proxy 本地开发代理,解决调试跨域

H5 路由建议:

txt 复制代码
部署简单:使用 hash 模式
追求 URL 美观:使用 history 模式,但服务器必须配置 fallback 到 index.html

8.4 微信小程序配置

json 复制代码
{
  "mp-weixin": {
    "appid": "wx1234567890abcdef",
    "setting": {
      "urlCheck": true,
      "es6": true,
      "postcss": true,
      "minified": true
    },
    "usingComponents": true,
    "permission": {
      "scope.userLocation": {
        "desc": "用于获取附近门店和配送地址"
      }
    }
  }
}

常用说明:

配置 作用
appid 微信小程序 AppID
setting.urlCheck 是否校验合法域名
setting.es6 是否启用 ES6 转换
setting.minified 是否压缩代码
permission 小程序权限说明

注意:

txt 复制代码
1. 小程序上线必须使用正式 AppID。
2. 请求接口必须配置合法域名。
3. 接口建议使用 HTTPS。
4. 用到定位、相册、摄像头等能力时,要配置权限说明。
5. 涉及用户隐私信息时,需要在小程序后台配置用户隐私保护指引。

8.5 App 配置 app-plus

json 复制代码
{
  "app-plus": {
    "usingComponents": true,
    "nvueStyleCompiler": "uni-app",
    "compilerVersion": 3,
    "splashscreen": {
      "alwaysShowBeforeRender": true,
      "waiting": true,
      "autoclose": true,
      "delay": 0
    },
    "modules": {
      "Camera": {},
      "Gallery": {},
      "Geolocation": {},
      "OAuth": {},
      "Payment": {},
      "Share": {}
    },
    "distribute": {
      "android": {
        "packagename": "com.example.uniappshop",
        "permissions": [
          "<uses-permission android:name=\"android.permission.INTERNET\"/>",
          "<uses-permission android:name=\"android.permission.CAMERA\"/>"
        ]
      },
      "ios": {
        "appid": "com.example.uniappshop"
      },
      "sdkConfigs": {}
    }
  }
}

常用说明:

配置 作用
splashscreen App 启动图相关
modules App 原生模块,如相机、定位、支付、分享
distribute.android.packagename Android 包名
distribute.android.permissions Android 权限
distribute.ios.appid iOS Bundle ID
sdkConfigs 第三方 SDK 配置

8.6 App 图标和启动图

发布 App 前必须配置:

txt 复制代码
1. App 图标
2. 启动图
3. 应用名称
4. 包名 / Bundle ID
5. 版本名称 versionName
6. 版本号 versionCode
7. 权限说明
8. 签名证书

建议:

txt 复制代码
图标:1024x1024 PNG,避免透明背景
启动图:按平台要求准备多尺寸
应用名称:不要频繁变更
包名:一旦上架,后续不要更换
版本号:每次发版必须递增

9. package.json、vite.config.ts 和环境变量

9.1 package.json 常用 scripts

json 复制代码
{
  "scripts": {
    "dev:h5": "uni -p h5",
    "build:h5": "uni build -p h5",
    "dev:mp-weixin": "uni -p mp-weixin",
    "build:mp-weixin": "uni build -p mp-weixin",
    "dev:app": "uni -p app",
    "build:app": "uni build -p app"
  }
}

9.2 环境变量

建议建立:

txt 复制代码
.env.development
.env.production
.env.test

.env.development

env 复制代码
VITE_APP_ENV=development
VITE_API_BASE_URL=https://dev-api.example.com

.env.production

env 复制代码
VITE_APP_ENV=production
VITE_API_BASE_URL=https://api.example.com

读取环境变量:

ts 复制代码
export const ENV = {
  appEnv: import.meta.env.VITE_APP_ENV,
  apiBaseUrl: import.meta.env.VITE_API_BASE_URL
}

9.3 vite.config.ts 示例

ts 复制代码
import { defineConfig } from 'vite'
import uni from '@dcloudio/vite-plugin-uni'
import path from 'path'

export default defineConfig({
  plugins: [uni()],
  resolve: {
    alias: {
      '@': path.resolve(__dirname, 'src')
    }
  }
})

10. 页面、组件和基础语法

10.1 页面基础写法

vue 复制代码
<template>
  <view class="page">
    <text class="title">首页</text>

    <button @click="goDetail">进入详情页</button>
  </view>
</template>

<script setup lang="ts">
const goDetail = () => {
  uni.navigateTo({
    url: '/pages/goods/detail?id=100'
  })
}
</script>

<style scoped lang="scss">
.page {
  min-height: 100vh;
  padding: 32rpx;
  background: #f5f5f5;
}

.title {
  font-size: 36rpx;
  font-weight: 600;
}
</style>

10.2 常用标签对比

HTML uni-app 推荐组件 说明
div view 容器
span text 文本
img image 图片
a navigator 页面跳转
input input 输入框
button button 按钮
textarea textarea 多行输入
ul/li view 列表通常用 view 实现

10.3 组件示例

components/GoodsCard/GoodsCard.vue

vue 复制代码
<template>
  <view class="goods-card" @click="handleClick">
    <image class="goods-image" :src="goods.image" mode="aspectFill" />
    <view class="goods-info">
      <text class="goods-title">{{ goods.title }}</text>
      <text class="goods-price">¥{{ goods.price }}</text>
    </view>
  </view>
</template>

<script setup lang="ts">
interface Goods {
  id: number
  title: string
  image: string
  price: number
}

const props = defineProps<{
  goods: Goods
}>()

const emit = defineEmits<{
  click: [goods: Goods]
}>()

const handleClick = () => {
  emit('click', props.goods)
}
</script>

<style scoped lang="scss">
.goods-card {
  display: flex;
  padding: 24rpx;
  border-radius: 20rpx;
  background: #fff;
}

.goods-image {
  width: 160rpx;
  height: 160rpx;
  border-radius: 12rpx;
}

.goods-info {
  flex: 1;
  margin-left: 24rpx;
}

.goods-title {
  display: block;
  font-size: 30rpx;
  color: #222;
}

.goods-price {
  display: block;
  margin-top: 20rpx;
  font-size: 32rpx;
  color: #f53f3f;
  font-weight: 600;
}
</style>

页面使用:

vue 复制代码
<template>
  <GoodsCard :goods="item" @click="goDetail" />
</template>

11. 路由跳转和登录拦截

uni-app 常用路由 API:

API 作用 使用场景
uni.navigateTo 保留当前页,跳转非 tabBar 页面 列表到详情
uni.redirectTo 关闭当前页,跳转新页面 登录页跳转
uni.reLaunch 关闭所有页面,打开指定页面 退出登录
uni.switchTab 跳转 tabBar 页面 首页、分类、我的
uni.navigateBack 返回上一页 详情返回列表

11.1 封装 router.ts

ts 复制代码
// utils/router.ts
const whiteList = [
  '/pages/login/index',
  '/pages/register/index',
  '/pages/index/index'
]

export function getToken() {
  return uni.getStorageSync('token')
}

export function isWhitePage(url: string) {
  return whiteList.some(item => url.startsWith(item))
}

export function navigateTo(url: string) {
  if (!getToken() && !isWhitePage(url)) {
    uni.redirectTo({
      url: '/pages/login/index'
    })
    return
  }

  uni.navigateTo({ url })
}

export function redirectTo(url: string) {
  uni.redirectTo({ url })
}

export function switchTab(url: string) {
  if (!getToken() && !isWhitePage(url)) {
    uni.redirectTo({
      url: '/pages/login/index'
    })
    return
  }

  uni.switchTab({ url })
}

export function reLaunch(url: string) {
  uni.reLaunch({ url })
}

11.2 页面使用

ts 复制代码
import { navigateTo } from '@/utils/router'

navigateTo('/pages/goods/detail?id=100')

11.3 为什么不完全照搬 Vue Router?

uni-app 不是传统 Web SPA,它要兼容小程序和 App,因此没有完全等同于 Vue Router 的全局路由守卫。实际项目中更推荐:

txt 复制代码
1. 统一封装跳转方法
2. 所有页面跳转都通过封装方法
3. 请求层统一处理 401
4. 页面 onLoad 中做兜底验证
5. 特殊平台差异用条件编译处理

12. 网络请求封装

12.1 基础请求

ts 复制代码
uni.request({
  url: 'https://api.example.com/user',
  method: 'GET',
  success(res) {
    console.log(res.data)
  },
  fail(err) {
    console.log(err)
  }
})

12.2 企业级请求封装

utils/request.ts

ts 复制代码
import { ENV } from '@/utils/env'

type Method = 'GET' | 'POST' | 'PUT' | 'DELETE'

interface RequestOptions {
  url: string
  method?: Method
  data?: Record<string, any>
  header?: Record<string, string>
  showLoading?: boolean
}

interface ApiResponse<T = any> {
  code: number
  message: string
  data: T
}

const BASE_URL = ENV.apiBaseUrl

export function request<T = any>(options: RequestOptions): Promise<T> {
  const token = uni.getStorageSync('token')

  if (options.showLoading !== false) {
    uni.showLoading({
      title: '加载中',
      mask: true
    })
  }

  return new Promise((resolve, reject) => {
    uni.request({
      url: BASE_URL + options.url,
      method: options.method || 'GET',
      data: options.data || {},
      header: {
        'Content-Type': 'application/json',
        Authorization: token ? `Bearer ${token}` : '',
        ...options.header
      },
      success(res) {
        const result = res.data as ApiResponse<T>

        if (res.statusCode === 200 && result.code === 0) {
          resolve(result.data)
          return
        }

        if (res.statusCode === 401 || result.code === 401) {
          uni.removeStorageSync('token')
          uni.redirectTo({
            url: '/pages/login/index'
          })
          reject(result)
          return
        }

        uni.showToast({
          title: result.message || '请求失败',
          icon: 'none'
        })

        reject(result)
      },
      fail(err) {
        uni.showToast({
          title: '网络异常,请稍后重试',
          icon: 'none'
        })
        reject(err)
      },
      complete() {
        if (options.showLoading !== false) {
          uni.hideLoading()
        }
      }
    })
  })
}

12.3 接口模块

api/user.ts

ts 复制代码
import { request } from '@/utils/request'

export interface LoginParams {
  username: string
  password: string
}

export interface LoginResult {
  token: string
  userInfo: {
    id: number
    nickname: string
    avatar: string
  }
}

export function loginApi(data: LoginParams) {
  return request<LoginResult>({
    url: '/auth/login',
    method: 'POST',
    data
  })
}

export function getUserInfoApi() {
  return request({
    url: '/user/info',
    method: 'GET'
  })
}

12.4 H5、小程序、App 请求差异

平台 请求注意点
H5 有浏览器跨域问题,本地可用 devServer.proxy,线上要后端配置 CORS 或同域代理
微信小程序 必须配置 request 合法域名,正式环境通常必须 HTTPS
App 一般没有浏览器跨域限制,但要注意证书、HTTPS、弱网、超时
多端通用 token、错误码、loading、重试、刷新 token 要统一封装

13. 本地缓存封装

13.1 基础用法

ts 复制代码
uni.setStorageSync('token', 'abc')

const token = uni.getStorageSync('token')

uni.removeStorageSync('token')

uni.clearStorageSync()

13.2 封装 storage.ts

ts 复制代码
// utils/storage.ts
export const storage = {
  set<T = any>(key: string, value: T) {
    uni.setStorageSync(key, value)
  },

  get<T = any>(key: string): T | null {
    const value = uni.getStorageSync(key)
    return value || null
  },

  remove(key: string) {
    uni.removeStorageSync(key)
  },

  clear() {
    uni.clearStorageSync()
  }
}

13.3 常见缓存内容

内容 key 示例
token token
用户信息 userInfo
搜索历史 searchHistory
主题配置 theme
首次启动标记 hasOpened
定位城市 locationCity

14. Pinia 状态管理

14.1 安装

bash 复制代码
npm install pinia

14.2 注册 Pinia

main.ts

ts 复制代码
import { createSSRApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'

export function createApp() {
  const app = createSSRApp(App)
  const pinia = createPinia()

  app.use(pinia)

  return {
    app
  }
}

14.3 用户 Store

stores/user.ts

ts 复制代码
import { defineStore } from 'pinia'
import { loginApi, LoginParams } from '@/api/user'

interface UserInfo {
  id: number
  nickname: string
  avatar: string
}

export const useUserStore = defineStore('user', {
  state: () => ({
    token: uni.getStorageSync('token') || '',
    userInfo: uni.getStorageSync('userInfo') as UserInfo | null
  }),

  getters: {
    isLogin: state => !!state.token
  },

  actions: {
    async login(params: LoginParams) {
      const res = await loginApi(params)

      this.token = res.token
      this.userInfo = res.userInfo

      uni.setStorageSync('token', res.token)
      uni.setStorageSync('userInfo', res.userInfo)
    },

    logout() {
      this.token = ''
      this.userInfo = null

      uni.removeStorageSync('token')
      uni.removeStorageSync('userInfo')

      uni.reLaunch({
        url: '/pages/login/index'
      })
    }
  }
})

15. 生命周期详细讲解

uni-app 生命周期主要分为:

txt 复制代码
应用生命周期
页面生命周期
组件生命周期

15.1 应用生命周期

写在 App.vue

vue 复制代码
<script lang="ts">
export default {
  onLaunch() {
    console.log('App 启动')
  },

  onShow() {
    console.log('App 显示')
  },

  onHide() {
    console.log('App 隐藏')
  },

  onError(error: string) {
    console.log('App 错误', error)
  }
}
</script>
生命周期 说明 常用场景
onLaunch 应用初始化 读取缓存、初始化 SDK
onShow 应用进入前台 刷新状态、检查登录
onHide 应用进入后台 暂停任务、保存状态
onError 应用报错 错误上报

15.2 页面生命周期

vue 复制代码
<script setup lang="ts">
import {
  onLoad,
  onShow,
  onReady,
  onHide,
  onUnload,
  onPullDownRefresh,
  onReachBottom
} from '@dcloudio/uni-app'

onLoad((options) => {
  console.log('页面加载参数', options)
})

onShow(() => {
  console.log('页面显示')
})

onReady(() => {
  console.log('页面初次渲染完成')
})

onHide(() => {
  console.log('页面隐藏')
})

onUnload(() => {
  console.log('页面卸载')
})

onPullDownRefresh(() => {
  console.log('下拉刷新')
  uni.stopPullDownRefresh()
})

onReachBottom(() => {
  console.log('触底加载更多')
})
</script>
生命周期 说明 常用场景
onLoad 页面加载 接收参数、请求详情
onShow 页面显示 每次进入刷新
onReady 首次渲染完成 获取节点信息
onHide 页面隐藏 暂停视频、保存草稿
onUnload 页面卸载 清理定时器
onPullDownRefresh 下拉刷新 刷新列表
onReachBottom 触底 分页加载
onShareAppMessage 小程序分享 自定义分享

16. 样式、rpx、flex 和安全区适配

16.1 rpx 是什么?

rpx 是响应式单位。uni-app 以 750rpx 作为屏幕宽度基准。

txt 复制代码
屏幕宽度 = 750rpx
设计稿 750px 时:1px ≈ 1rpx
设计稿 375px 时:1px ≈ 2rpx

示例:

scss 复制代码
.card {
  width: 702rpx;
  margin: 24rpx;
  padding: 32rpx;
  border-radius: 20rpx;
  background: #fff;
}

16.2 单位使用建议

场景 推荐单位
宽度 rpx、%
高度 rpx、px
间距 rpx
字体 rpx 或 px
边框 1px
H5 响应式 vw、vh、%、媒体查询
App 原生导航相关 px

16.3 flex 布局建议

scss 复制代码
.row {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.column {
  display: flex;
  flex-direction: column;
}

.flex-1 {
  flex: 1;
  min-width: 0;
}

16.4 安全区适配

iPhone 底部安全区适配:

scss 复制代码
.safe-bottom {
  padding-bottom: constant(safe-area-inset-bottom);
  padding-bottom: env(safe-area-inset-bottom);
}

底部固定按钮:

vue 复制代码
<template>
  <view class="bottom-bar safe-bottom">
    <button class="submit-btn">提交订单</button>
  </view>
</template>

<style scoped lang="scss">
.bottom-bar {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  padding: 20rpx 24rpx;
  background: #fff;
  box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.06);
}

.submit-btn {
  height: 88rpx;
  line-height: 88rpx;
  border-radius: 44rpx;
  background: #1677ff;
  color: #fff;
}
</style>

16.5 自定义导航栏适配

获取状态栏高度:

ts 复制代码
const systemInfo = uni.getSystemInfoSync()

const statusBarHeight = systemInfo.statusBarHeight || 0

自定义导航栏示例:

vue 复制代码
<template>
  <view class="navbar" :style="{ paddingTop: statusBarHeight + 'px' }">
    <view class="navbar-content">
      <text class="title">首页</text>
    </view>
  </view>
</template>

<script setup lang="ts">
const systemInfo = uni.getSystemInfoSync()
const statusBarHeight = systemInfo.statusBarHeight || 0
</script>

<style scoped lang="scss">
.navbar {
  background: #fff;
}

.navbar-content {
  height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.title {
  font-size: 32rpx;
  font-weight: 600;
}
</style>

17. 条件编译详细讲解

条件编译用于处理平台差异,是 uni-app 实现一套代码多端适配的关键能力。

17.1 常用平台标识

平台 条件编译标识
H5 H5
App APP-PLUS
微信小程序 MP-WEIXIN
支付宝小程序 MP-ALIPAY
抖音小程序 MP-TOUTIAO
百度小程序 MP-BAIDU
QQ 小程序 MP-QQ
所有小程序 MP

17.2 JS / TS 中使用

ts 复制代码
// #ifdef H5
console.log('只在 H5 执行')
// #endif

// #ifdef MP-WEIXIN
console.log('只在微信小程序执行')
// #endif

// #ifdef APP-PLUS
console.log('只在 App 执行')
// #endif

17.3 template 中使用

vue 复制代码
<template>
  <view>
    <!-- #ifdef H5 -->
    <view>H5 专属内容</view>
    <!-- #endif -->

    <!-- #ifdef MP-WEIXIN -->
    <view>微信小程序专属内容</view>
    <!-- #endif -->

    <!-- #ifdef APP-PLUS -->
    <view>App 专属内容</view>
    <!-- #endif -->
  </view>
</template>

17.4 CSS 中使用

scss 复制代码
.page {
  min-height: 100vh;
}

/* #ifdef H5 */
.page {
  padding-top: 20px;
}
/* #endif */

/* #ifdef MP-WEIXIN */
.page {
  padding-top: 20rpx;
}
/* #endif */

/* #ifdef APP-PLUS */
.page {
  padding-top: 0;
}
/* #endif */

17.5 多条件判断

ts 复制代码
// #ifdef H5 || MP-WEIXIN
console.log('H5 或微信小程序执行')
// #endif

// #ifndef H5
console.log('非 H5 平台执行')
// #endif

17.6 条件编译使用原则

txt 复制代码
1. 能用统一 API 就不要条件编译。
2. 条件编译只处理真正的平台差异。
3. 平台差异代码集中放到 platform 目录。
4. 不要在业务页面到处散落大量 #ifdef。
5. 对支付、登录、分享、权限等能力做统一封装。

18. 一套代码如何适配 H5、小程序、App 三端

这是 uni-app 项目最重要的工程能力。

18.1 核心思想

txt 复制代码
公共业务逻辑统一
公共页面结构统一
公共组件统一
公共 API 封装统一
公共状态管理统一

平台差异通过:
1. 条件编译
2. 适配层封装
3. manifest.json 平台配置
4. pages.json 多端路由配置
5. 样式单位和安全区适配
6. 平台专属模块隔离

18.2 三端差异总览

差异点 H5 小程序 App
运行环境 浏览器 小程序容器 原生 App 容器
请求限制 跨域 CORS 合法域名限制 通常无浏览器跨域
路由 浏览器路由 小程序页面栈 App 页面栈
支付 H5 支付 微信/支付宝小程序支付 App 支付 SDK
分享 Web Share / 链接分享 小程序分享 系统分享 / SDK 分享
登录 账号密码、短信、OAuth 微信登录、手机号授权 手机号、OAuth、第三方登录
定位 浏览器定位 小程序定位权限 系统定位权限
文件上传 input/file 或 uni.chooseImage 小程序文件能力 App 原生文件能力
审核 不需要平台审核 小程序审核 应用市场审核
更新 部署服务器即可 提交审核发布 发版或热更新

18.3 统一组件写法

正确做法:

vue 复制代码
<template>
  <view class="page">
    <text>标题</text>
    <image src="/static/logo.png" mode="aspectFit" />
  </view>
</template>

不推荐:

vue 复制代码
<template>
  <div>
    <span>标题</span>
    <img src="/static/logo.png" />
  </div>
</template>

虽然部分 HTML 标签在某些端可以被转换,但多端项目建议统一使用 uni-app 组件:

txt 复制代码
view
text
image
button
input
textarea
scroll-view
swiper
navigator

18.4 统一请求层

不要在页面中直接写:

ts 复制代码
uni.request(...)

而是统一走:

ts 复制代码
request({
  url: '/goods/list',
  method: 'GET'
})

优势:

txt 复制代码
1. H5、小程序、App 共用同一套接口调用方式。
2. token 自动携带。
3. 401 自动跳登录。
4. 错误提示统一。
5. loading 统一。
6. 后续切换 baseURL 更方便。

18.5 统一路由层

不要到处直接写:

ts 复制代码
uni.navigateTo(...)

建议统一走:

ts 复制代码
navigateTo('/pages/goods/detail?id=1')

好处:

txt 复制代码
1. 可以统一做登录拦截。
2. 可以区分 tabBar 和非 tabBar。
3. 可以统一处理页面不存在。
4. 可以记录埋点。

18.6 统一平台能力适配层

推荐目录:

txt 复制代码
platform
├─ login.ts
├─ pay.ts
├─ share.ts
├─ location.ts
└─ permission.ts
18.6.1 登录适配

platform/login.ts

ts 复制代码
export async function platformLogin() {
  // #ifdef MP-WEIXIN
  return new Promise((resolve, reject) => {
    uni.login({
      provider: 'weixin',
      success: resolve,
      fail: reject
    })
  })
  // #endif

  // #ifdef H5
  return Promise.resolve({
    type: 'h5',
    message: 'H5 使用账号密码或短信登录'
  })
  // #endif

  // #ifdef APP-PLUS
  return Promise.resolve({
    type: 'app',
    message: 'App 可接入手机号、微信、苹果等登录方式'
  })
  // #endif
}
18.6.2 支付适配

platform/pay.ts

ts 复制代码
interface PayParams {
  provider?: string
  orderInfo: any
}

export function pay(params: PayParams) {
  // #ifdef MP-WEIXIN
  return new Promise((resolve, reject) => {
    uni.requestPayment({
      provider: 'wxpay',
      ...params.orderInfo,
      success: resolve,
      fail: reject
    })
  })
  // #endif

  // #ifdef H5
  window.location.href = params.orderInfo.payUrl
  return Promise.resolve()
  // #endif

  // #ifdef APP-PLUS
  return new Promise((resolve, reject) => {
    uni.requestPayment({
      provider: params.provider || 'wxpay',
      orderInfo: params.orderInfo,
      success: resolve,
      fail: reject
    })
  })
  // #endif
}
18.6.3 分享适配

platform/share.ts

ts 复制代码
interface ShareOptions {
  title: string
  path?: string
  imageUrl?: string
  url?: string
}

export function share(options: ShareOptions) {
  // #ifdef H5
  if (navigator.share) {
    return navigator.share({
      title: options.title,
      url: options.url
    })
  }

  uni.setClipboardData({
    data: options.url || '',
    success() {
      uni.showToast({
        title: '链接已复制',
        icon: 'none'
      })
    }
  })
  // #endif

  // #ifdef APP-PLUS
  uni.share({
    provider: 'weixin',
    scene: 'WXSceneSession',
    type: 0,
    href: options.url,
    title: options.title,
    imageUrl: options.imageUrl
  })
  // #endif
}

小程序分享通常写在页面生命周期:

ts 复制代码
import { onShareAppMessage } from '@dcloudio/uni-app'

onShareAppMessage(() => {
  return {
    title: '商品详情',
    path: '/pages/goods/detail?id=100',
    imageUrl: '/static/share.png'
  }
})

18.7 统一样式规范

推荐:

scss 复制代码
/* styles/common.scss */
.page {
  min-height: 100vh;
  background: #f5f5f5;
}

.container {
  padding: 24rpx;
}

.card {
  border-radius: 20rpx;
  background: #fff;
}

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

.safe-bottom {
  padding-bottom: constant(safe-area-inset-bottom);
  padding-bottom: env(safe-area-inset-bottom);
}

18.8 环境变量适配三端

ts 复制代码
// utils/env.ts
const env = import.meta.env.VITE_APP_ENV

const baseURLMap: Record<string, string> = {
  development: 'https://dev-api.example.com',
  test: 'https://test-api.example.com',
  production: 'https://api.example.com'
}

export const ENV = {
  env,
  apiBaseUrl: baseURLMap[env] || baseURLMap.production
}

18.9 图片资源适配

建议:

txt 复制代码
1. 本地固定资源放 static。
2. 后台图片使用完整 HTTPS 地址。
3. 小程序远程图片域名要在后台配置。
4. App 图片要注意 http/https 和证书问题。
5. H5 图片要注意跨域、CDN、缓存。

正确:

vue 复制代码
<image src="/static/logo.png" mode="aspectFit" />
<image :src="goods.imageUrl" mode="aspectFill" />

18.10 一套代码适配三端的推荐架构

txt 复制代码
页面层 pages
  只写业务展示和用户交互

组件层 components
  只写通用 UI,不直接依赖平台能力

业务接口层 api
  统一管理接口

基础工具层 utils
  request、router、storage、validate

状态管理 stores
  管理 token、userInfo、cart、settings

平台能力层 platform
  登录、支付、分享、定位、权限

条件编译
  只放在 platform 层或少量平台差异 UI

19. H5 发布流程和配置

H5 发布本质是把 uni-app 项目打包成 Web 静态资源,然后部署到服务器。

19.1 H5 发布流程总览

txt 复制代码
1. 配置 manifest.json 的 h5
2. 配置生产接口地址
3. 执行 H5 打包
4. 得到 H5 静态文件
5. 上传到服务器
6. 配置 Nginx / Apache
7. 配置 HTTPS
8. 测试页面、接口、刷新、路由、静态资源
9. 正式上线

19.2 manifest.json H5 配置

json 复制代码
{
  "h5": {
    "title": "uni-app 商城",
    "router": {
      "mode": "hash",
      "base": "/"
    },
    "optimization": {
      "treeShaking": {
        "enable": true
      }
    },
    "devServer": {
      "port": 5173,
      "https": false,
      "proxy": {
        "/api": {
          "target": "https://api.example.com",
          "changeOrigin": true,
          "secure": false
        }
      }
    }
  }
}

19.3 hash 和 history 如何选择?

路由模式 URL 示例 优点 缺点
hash https://example.com/#/pages/index/index 部署简单,刷新不 404 URL 不够美观
history https://example.com/pages/index/index URL 美观 服务器要配置 fallback

新手建议:

txt 复制代码
先用 hash,等项目稳定后再考虑 history。

19.4 H5 打包命令

HBuilderX:

txt 复制代码
发行
→ 网站 - H5 手机版
→ 生成 H5 资源

CLI:

bash 复制代码
npm run build:h5

常见产物目录:

txt 复制代码
HBuilderX 项目:unpackage/dist/build/h5
CLI 项目:dist/build/h5

19.5 Nginx 部署 hash 模式

nginx 复制代码
server {
  listen 80;
  server_name example.com;

  root /www/wwwroot/uni-h5;
  index index.html;

  location / {
    try_files $uri $uri/ /index.html;
  }

  location /api/ {
    proxy_pass https://api.example.com/;
    proxy_set_header Host api.example.com;
    proxy_set_header X-Real-IP $remote_addr;
  }
}

19.6 Nginx 部署 history 模式

nginx 复制代码
server {
  listen 80;
  server_name example.com;

  root /www/wwwroot/uni-h5;
  index index.html;

  location / {
    try_files $uri $uri/ /index.html;
  }
}

如果刷新 404,基本就是没有配置:

nginx 复制代码
try_files $uri $uri/ /index.html;

19.7 H5 常见上线问题

问题 原因 解决
页面刷新 404 history 没配置 fallback Nginx 配置 try_files
接口跨域 后端未配置 CORS 后端允许跨域或 Nginx 反向代理
静态资源 404 base 路径错误 检查 router.base 和部署目录
白屏 JS 资源加载失败 看浏览器 Network
图片不显示 路径错误或跨域 使用绝对地址或 CDN
首屏慢 资源太大 gzip、CDN、图片压缩、懒加载

19.8 H5 上线检查

txt 复制代码
1. 是否使用生产接口。
2. 是否开启 HTTPS。
3. 是否处理跨域。
4. 页面刷新是否正常。
5. 静态资源是否加载成功。
6. 手机浏览器是否正常。
7. 微信内置浏览器是否正常。
8. 分享标题、描述、图片是否正确。
9. 埋点、统计是否正常。
10. 404、500 页面是否处理。

20. 微信小程序发布流程和配置

20.1 微信小程序发布流程总览

txt 复制代码
1. 注册微信小程序账号
2. 获取小程序 AppID
3. 在 manifest.json 配置 mp-weixin.appid
4. 配置服务器域名
5. 配置隐私协议和权限说明
6. HBuilderX 或 CLI 打包微信小程序
7. 用微信开发者工具导入打包目录
8. 真机预览测试
9. 上传代码
10. 微信公众平台提交审核
11. 审核通过后发布

20.2 注册和准备

需要准备:

txt 复制代码
1. 微信公众平台账号
2. 小程序 AppID
3. 小程序名称
4. 小程序头像
5. 服务类目
6. 服务器域名
7. 隐私保护指引
8. 业务资质材料,例如电商、医疗、教育等场景

微信公众平台:

https://mp.weixin.qq.com/

微信小程序官方文档:

https://developers.weixin.qq.com/miniprogram/dev/framework/

20.3 manifest.json 微信小程序配置

json 复制代码
{
  "mp-weixin": {
    "appid": "wx1234567890abcdef",
    "setting": {
      "urlCheck": true,
      "es6": true,
      "postcss": true,
      "minified": true,
      "newFeature": true
    },
    "usingComponents": true,
    "permission": {
      "scope.userLocation": {
        "desc": "用于为你推荐附近门店和计算配送距离"
      }
    }
  }
}

20.4 服务器域名配置

在微信公众平台配置:

txt 复制代码
微信公众平台
→ 开发
→ 开发管理
→ 开发设置
→ 服务器域名

常见域名类型:

类型 用途
request 合法域名 uni.request 请求接口
socket 合法域名 WebSocket
uploadFile 合法域名 上传文件
downloadFile 合法域名 下载文件
udp 合法域名 UDP 通信

注意:

txt 复制代码
1. 正式环境域名必须 HTTPS。
2. 不能直接用 IP。
3. 域名需要备案和可访问。
4. 本地开发可以在开发者工具里勾选"不校验合法域名",但上线不行。
5. 接口域名、图片域名、上传域名要分别检查。

20.5 小程序权限配置

如果用到定位:

json 复制代码
{
  "mp-weixin": {
    "permission": {
      "scope.userLocation": {
        "desc": "用于获取当前位置,展示附近门店"
      }
    }
  }
}

常见权限:

权限 场景
scope.userLocation 定位
摄像头 扫码、拍照
相册 上传图片
录音 语音输入
通知 订阅消息

20.6 小程序分包优化

当项目变大时,建议使用分包:

json 复制代码
{
  "subPackages": [
    {
      "root": "pages-sub/order",
      "pages": [
        {
          "path": "list",
          "style": {
            "navigationBarTitleText": "订单列表"
          }
        }
      ]
    }
  ]
}

优化建议:

txt 复制代码
1. 首页和 tabBar 放主包。
2. 订单、活动、设置、详情放分包。
3. 大图片不要放进主包。
4. 静态资源尽量使用 CDN。
5. 组件库按需引入。

20.7 打包微信小程序

HBuilderX:

txt 复制代码
发行
→ 小程序 - 微信
→ 输入小程序名称和 AppID
→ 发行

CLI:

bash 复制代码
npm run build:mp-weixin

产物目录:

txt 复制代码
HBuilderX 项目:unpackage/dist/build/mp-weixin
CLI 项目:dist/build/mp-weixin

20.8 微信开发者工具导入

txt 复制代码
打开微信开发者工具
→ 导入项目
→ 选择 mp-weixin 打包产物目录
→ 填写 AppID
→ 编译运行
→ 真机预览
→ 上传代码

20.9 上传和审核

txt 复制代码
微信开发者工具
→ 上传
→ 填写版本号和项目备注
→ 上传成功

微信公众平台
→ 版本管理
→ 开发版本
→ 提交审核
→ 填写审核信息
→ 等待审核
→ 审核通过
→ 发布

20.10 小程序审核常见被拒原因

被拒原因 解决方案
服务类目不匹配 修改服务类目或调整业务描述
隐私协议未配置 在后台补充隐私保护指引
诱导分享/诱导关注 删除相关文案和逻辑
登录强制授权 非必要场景不要强制登录
页面无法访问 检查接口域名、测试账号
内容违规 修改图片、文案、商品
支付能力未开通 先申请微信支付
资质不足 补充营业执照、行业资质
体验路径不清楚 提供测试账号和操作说明

20.11 小程序上线检查

txt 复制代码
1. 使用正式 AppID。
2. 接口域名已配置。
3. 图片、上传、下载域名已配置。
4. 隐私协议已配置。
5. 权限说明已配置。
6. 支付能力已开通。
7. 分包体积符合要求。
8. 真机预览正常。
9. 提供审核测试账号。
10. 页面无空白、无测试数据、无调试按钮。

21. App 发布流程和配置

uni-app 发布 App 分为:

txt 复制代码
Android App
iOS App

常见打包方式:

txt 复制代码
1. 云打包:HBuilderX 提交到 DCloud 云端打包,适合大多数项目。
2. 离线打包:使用 Android Studio / Xcode 原生工程打包,适合深度原生定制。

21.1 App 发布流程总览

txt 复制代码
1. 配置 manifest.json
2. 配置应用名称、图标、启动图
3. 配置包名 / Bundle ID
4. 配置版本号
5. 配置权限和 SDK
6. 准备签名证书
7. 运行真机测试
8. 云打包生成 APK / AAB / IPA
9. Android 提交应用市场
10. iOS 提交 App Store Connect
11. 等待审核
12. 审核通过后上架

21.2 App manifest.json 基础配置

json 复制代码
{
  "name": "uniapp-shop",
  "appid": "__UNI__XXXXXXX",
  "description": "uni-app 商城项目",
  "versionName": "1.0.0",
  "versionCode": 100,
  "app-plus": {
    "usingComponents": true,
    "nvueStyleCompiler": "uni-app",
    "compilerVersion": 3,
    "splashscreen": {
      "alwaysShowBeforeRender": true,
      "waiting": true,
      "autoclose": true,
      "delay": 0
    },
    "modules": {
      "Camera": {},
      "Gallery": {},
      "Geolocation": {},
      "OAuth": {},
      "Payment": {},
      "Share": {}
    }
  }
}

21.3 Android 配置

Android 需要重点配置:

txt 复制代码
1. 应用包名 packageName
2. 应用签名证书 keystore
3. 版本名称 versionName
4. 版本号 versionCode
5. 权限
6. 应用图标
7. 启动图
8. 打包格式 APK / AAB
21.3.1 Android 包名

推荐规则:

txt 复制代码
com.公司名.项目名

示例:

txt 复制代码
com.example.uniappshop
com.zengzhanwen.shop

注意:

txt 复制代码
1. 包名是应用唯一标识。
2. 上架后不要更换包名。
3. 更新版本必须使用相同包名。
4. 更新版本必须使用相同签名。
21.3.2 Android 证书

如果是正式商业项目,建议自己生成并保管证书。

生成 keystore 示例:

bash 复制代码
keytool -genkeypair \
  -alias uniappshop \
  -keyalg RSA \
  -keysize 2048 \
  -validity 36500 \
  -keystore uniappshop.keystore

需要保存:

txt 复制代码
证书文件:uniappshop.keystore
证书别名:uniappshop
证书库密码
证书密码

重要:

txt 复制代码
证书千万不要丢。
证书丢失后,很多应用市场无法正常更新旧版本。
21.3.3 Android 权限配置

常见权限:

xml 复制代码
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

权限建议:

txt 复制代码
1. 不需要的权限不要申请。
2. 用到相机、定位、存储时要有明确说明。
3. 国内应用市场对隐私权限审核较严格。
4. 首次打开不要一次性申请大量权限。
21.3.4 APK 和 AAB
格式 说明 适用
APK Android 安装包 国内应用市场、测试包
AAB Android App Bundle Google Play

建议:

txt 复制代码
国内市场:通常准备 APK。
Google Play:通常准备 AAB。

21.4 iOS 配置

iOS 需要重点配置:

txt 复制代码
1. Apple Developer Program 账号
2. Bundle ID
3. iOS 证书
4. 描述文件 Provisioning Profile
5. App Store Connect 应用记录
6. 隐私清单和权限说明
7. IPA 包
21.4.1 Bundle ID

格式示例:

txt 复制代码
com.example.uniappshop

注意:

txt 复制代码
1. Bundle ID 和 Android 包名类似,是 iOS 应用唯一标识。
2. 上架后不要随意更换。
3. 证书、描述文件、App Store Connect 需要保持一致。
21.4.2 iOS 权限说明

常见权限说明:

txt 复制代码
相机:用于拍摄头像、上传商品图片
相册:用于选择图片上传
定位:用于展示附近门店和配送地址
麦克风:用于录音或视频拍摄
通知:用于订单状态提醒

iOS 权限文案要写清楚,否则容易审核被拒。

21.5 App 云打包流程

HBuilderX:

txt 复制代码
发行
→ 原生 App - 云打包
→ 选择 Android / iOS
→ 填写包名 / Bundle ID
→ 选择证书
→ 选择打包格式
→ 提交云打包
→ 下载 APK / AAB / IPA

Android 云打包需要:

txt 复制代码
1. Android 包名
2. 证书类型
3. 证书文件
4. 证书密码
5. 证书别名
6. 打包格式 APK / AAB

iOS 云打包需要:

txt 复制代码
1. Bundle ID
2. iOS 发布证书
3. Provisioning Profile
4. Apple 相关配置

21.6 App 真机调试

建议流程:

txt 复制代码
1. 开发阶段使用运行到手机或自定义基座。
2. 测试相机、定位、上传、支付、分享、推送。
3. 弱网测试。
4. Android 多品牌手机测试。
5. iOS 多机型测试。
6. 测试安装、覆盖安装、卸载重装。

21.7 Android 上架流程

不同应用市场要求不同,但大致流程相似:

txt 复制代码
1. 注册开发者账号
2. 实名认证 / 企业认证
3. 创建应用
4. 填写应用名称、简介、分类、截图
5. 上传 APK / AAB
6. 填写隐私政策
7. 填写权限说明
8. 提交审核
9. 审核通过后上架

常见国内应用市场:

市场 地址
华为应用市场 https://developer.huawei.com/consumer/cn/
小米开放平台 https://dev.mi.com/
OPPO 开放平台 https://open.oppomobile.com/
vivo 开放平台 https://dev.vivo.com.cn/
腾讯应用宝 https://open.qq.com/
Google Play Console https://play.google.com/console

21.8 iOS 上架流程

txt 复制代码
1. 加入 Apple Developer Program
2. 创建 Bundle ID
3. 创建证书和描述文件
4. 在 App Store Connect 创建 App
5. 上传 IPA
6. 填写应用信息、截图、隐私信息
7. 选择构建版本
8. 提交审核
9. 审核通过后发布

相关地址:

平台 地址
Apple Developer https://developer.apple.com/
App Store Connect https://appstoreconnect.apple.com/
App Store Connect 文档 https://developer.apple.com/help/app-store-connect/

21.9 App 审核常见问题

问题 解决
权限申请过多 删除无用权限,补充用途说明
隐私政策不完整 增加隐私政策 URL 和权限说明
测试账号无法登录 提供可用账号和说明
支付不合规 按平台要求接入支付
App 崩溃 真机多机型测试,修复异常
内容违规 修改文案、图片和业务
版本号错误 versionCode 递增
签名错误 使用同一证书重新打包

22. 三端发布命令和产物目录

22.1 HBuilderX 项目

目标平台 操作 产物目录
H5 发行 → 网站 - H5 手机版 unpackage/dist/build/h5
微信小程序 发行 → 小程序 - 微信 unpackage/dist/build/mp-weixin
App 发行 → 原生 App - 云打包 APK / AAB / IPA

22.2 CLI 项目

目标平台 命令 产物目录
H5 npm run build:h5 dist/build/h5
微信小程序 npm run build:mp-weixin dist/build/mp-weixin
App 资源 npm run build:app dist/build/app 或相关 app 目录,具体以当前模板为准

22.3 发布前环境切换

建议:

txt 复制代码
开发环境:dev-api.example.com
测试环境:test-api.example.com
生产环境:api.example.com

不要把测试接口发布到正式环境。


23. 项目实战:登录、首页、列表、详情、个人中心

23.1 页面规划

txt 复制代码
pages/index/index        首页
pages/category/index     分类
pages/user/index         我的
pages/login/index        登录
pages/goods/detail       商品详情
pages-sub/order/list     订单列表
pages-sub/order/detail   订单详情

23.2 pages.json

json 复制代码
{
  "pages": [
    {
      "path": "pages/index/index",
      "style": {
        "navigationBarTitleText": "首页"
      }
    },
    {
      "path": "pages/category/index",
      "style": {
        "navigationBarTitleText": "分类"
      }
    },
    {
      "path": "pages/user/index",
      "style": {
        "navigationBarTitleText": "我的"
      }
    },
    {
      "path": "pages/login/index",
      "style": {
        "navigationBarTitleText": "登录"
      }
    },
    {
      "path": "pages/goods/detail",
      "style": {
        "navigationBarTitleText": "商品详情"
      }
    }
  ],
  "subPackages": [
    {
      "root": "pages-sub/order",
      "pages": [
        {
          "path": "list",
          "style": {
            "navigationBarTitleText": "订单列表"
          }
        },
        {
          "path": "detail",
          "style": {
            "navigationBarTitleText": "订单详情"
          }
        }
      ]
    }
  ],
  "globalStyle": {
    "navigationBarTextStyle": "black",
    "navigationBarTitleText": "商城",
    "navigationBarBackgroundColor": "#ffffff",
    "backgroundColor": "#f5f5f5"
  },
  "tabBar": {
    "color": "#666666",
    "selectedColor": "#1677ff",
    "backgroundColor": "#ffffff",
    "list": [
      {
        "pagePath": "pages/index/index",
        "text": "首页",
        "iconPath": "static/tabbar/home.png",
        "selectedIconPath": "static/tabbar/home-active.png"
      },
      {
        "pagePath": "pages/category/index",
        "text": "分类",
        "iconPath": "static/tabbar/category.png",
        "selectedIconPath": "static/tabbar/category-active.png"
      },
      {
        "pagePath": "pages/user/index",
        "text": "我的",
        "iconPath": "static/tabbar/user.png",
        "selectedIconPath": "static/tabbar/user-active.png"
      }
    ]
  }
}

23.3 登录页面

vue 复制代码
<template>
  <view class="login-page">
    <view class="logo">商城</view>

    <input
      v-model="form.username"
      class="input"
      placeholder="请输入账号"
    />

    <input
      v-model="form.password"
      class="input"
      password
      placeholder="请输入密码"
    />

    <button class="login-btn" @click="handleLogin">
      登录
    </button>
  </view>
</template>

<script setup lang="ts">
import { reactive } from 'vue'
import { useUserStore } from '@/stores/user'

const userStore = useUserStore()

const form = reactive({
  username: '',
  password: ''
})

const handleLogin = async () => {
  if (!form.username || !form.password) {
    uni.showToast({
      title: '请输入账号和密码',
      icon: 'none'
    })
    return
  }

  await userStore.login(form)

  uni.switchTab({
    url: '/pages/index/index'
  })
}
</script>

<style scoped lang="scss">
.login-page {
  min-height: 100vh;
  padding: 120rpx 48rpx;
  background: #fff;
}

.logo {
  margin-bottom: 80rpx;
  text-align: center;
  font-size: 48rpx;
  font-weight: 700;
}

.input {
  height: 88rpx;
  margin-bottom: 28rpx;
  padding: 0 28rpx;
  border-radius: 12rpx;
  background: #f5f5f5;
}

.login-btn {
  margin-top: 40rpx;
  height: 88rpx;
  line-height: 88rpx;
  border-radius: 44rpx;
  background: #1677ff;
  color: #fff;
}
</style>

23.4 分页列表 Hook

hooks/usePaging.ts

ts 复制代码
import { ref } from 'vue'

interface PagingOptions<T> {
  request: (params: { page: number; pageSize: number }) => Promise<{
    list: T[]
    total?: number
  }>
  pageSize?: number
}

export function usePaging<T>(options: PagingOptions<T>) {
  const page = ref(1)
  const pageSize = ref(options.pageSize || 10)
  const list = ref<T[]>([])
  const loading = ref(false)
  const finished = ref(false)

  const loadData = async (reset = false) => {
    if (loading.value) return
    if (finished.value && !reset) return

    loading.value = true

    if (reset) {
      page.value = 1
      list.value = []
      finished.value = false
    }

    try {
      const res = await options.request({
        page: page.value,
        pageSize: pageSize.value
      })

      const rows = res.list || []

      list.value.push(...rows)

      if (rows.length < pageSize.value) {
        finished.value = true
      } else {
        page.value++
      }
    } finally {
      loading.value = false
    }
  }

  return {
    page,
    pageSize,
    list,
    loading,
    finished,
    loadData
  }
}

23.5 首页列表

vue 复制代码
<template>
  <view class="page">
    <swiper class="banner" indicator-dots autoplay circular>
      <swiper-item v-for="item in banners" :key="item.id">
        <image class="banner-img" :src="item.image" mode="aspectFill" />
      </swiper-item>
    </swiper>

    <view class="goods-list">
      <GoodsCard
        v-for="item in list"
        :key="item.id"
        :goods="item"
        @click="goDetail"
      />
    </view>

    <view class="loading-text">
      {{ finished ? '没有更多了' : '加载中...' }}
    </view>
  </view>
</template>

<script setup lang="ts">
import { onLoad, onReachBottom, onPullDownRefresh } from '@dcloudio/uni-app'
import { usePaging } from '@/hooks/usePaging'
import { getGoodsListApi } from '@/api/goods'
import { navigateTo } from '@/utils/router'

const banners = [
  { id: 1, image: '/static/banner/banner1.png' },
  { id: 2, image: '/static/banner/banner2.png' }
]

const { list, finished, loadData } = usePaging({
  request: getGoodsListApi,
  pageSize: 10
})

const goDetail = (goods: any) => {
  navigateTo(`/pages/goods/detail?id=${goods.id}`)
}

onLoad(() => {
  loadData()
})

onReachBottom(() => {
  loadData()
})

onPullDownRefresh(async () => {
  await loadData(true)
  uni.stopPullDownRefresh()
})
</script>

<style scoped lang="scss">
.page {
  min-height: 100vh;
  background: #f5f5f5;
}

.banner {
  width: 100%;
  height: 320rpx;
}

.banner-img {
  width: 100%;
  height: 320rpx;
}

.goods-list {
  padding: 24rpx;
  display: flex;
  flex-direction: column;
  gap: 24rpx;
}

.loading-text {
  padding: 24rpx;
  text-align: center;
  font-size: 26rpx;
  color: #999;
}
</style>

24. 常见问题和解决方案

24.1 小程序请求失败

原因:

txt 复制代码
1. 没有配置 request 合法域名。
2. 接口不是 HTTPS。
3. 使用了 IP 或 localhost。
4. 证书不合法。
5. 开发者工具开启了校验域名。

解决:

txt 复制代码
1. 到微信公众平台配置服务器域名。
2. 使用正式 HTTPS 域名。
3. 开发阶段可临时关闭合法域名校验。
4. 真机测试前必须配置正确。

24.2 H5 跨域

原因:

txt 复制代码
浏览器同源策略限制。

解决:

txt 复制代码
1. 后端配置 CORS。
2. Nginx 反向代理。
3. 本地开发用 devServer.proxy。
4. 生产环境不要依赖本地代理。

24.3 tabBar 页面跳转失败

错误:

ts 复制代码
uni.navigateTo({
  url: '/pages/index/index'
})

正确:

ts 复制代码
uni.switchTab({
  url: '/pages/index/index'
})

24.4 页面刷新 404

原因:

txt 复制代码
H5 history 模式没有配置服务端 fallback。

解决:

nginx 复制代码
location / {
  try_files $uri $uri/ /index.html;
}

24.5 App 权限不生效

解决:

txt 复制代码
1. 检查 manifest.json 权限。
2. 检查 Android / iOS 原生权限说明。
3. 重新打包自定义基座或正式包。
4. 真机测试,不要只看浏览器。

24.6 图片不显示

可能原因:

txt 复制代码
1. 本地路径错误。
2. 图片没放 static。
3. 远程图片域名未配置。
4. 图片链接 http 被拦截。
5. 图片太大加载慢。

解决:

txt 复制代码
1. 本地图片使用 /static/logo.png。
2. 远程图片使用 HTTPS。
3. 小程序后台配置图片域名。
4. 图片上 CDN 并压缩。

24.7 scroll-view 性能差

解决:

txt 复制代码
1. 普通页面长列表优先用页面滚动 + onReachBottom。
2. 超长列表使用虚拟列表。
3. App 高性能列表考虑 nvue / list-view。
4. 图片懒加载。
5. 减少复杂阴影和圆角。

24.8 条件编译太乱

解决:

txt 复制代码
1. 条件编译不要散落在大量页面中。
2. 平台差异放 platform 目录。
3. 支付、分享、登录、权限统一封装。
4. 页面只调用统一方法。

25. 学习路线

第一阶段:Vue 基础

txt 复制代码
1. Vue3 模板语法
2. ref、reactive
3. computed、watch
4. props、emit
5. 组件封装
6. 生命周期
7. TypeScript 基础

第二阶段:uni-app 基础

txt 复制代码
1. 创建项目
2. 页面写法
3. view、text、image、button 等组件
4. pages.json
5. manifest.json
6. 路由跳转
7. 生命周期

第三阶段:项目能力

txt 复制代码
1. 请求封装
2. 登录注册
3. token 管理
4. Pinia 状态管理
5. 表单校验
6. 图片上传
7. 分页列表
8. 下拉刷新
9. 上拉加载

第四阶段:三端适配

txt 复制代码
1. H5 跨域和部署
2. 小程序合法域名和审核
3. App 权限和打包
4. 条件编译
5. 支付、分享、登录适配
6. 样式和安全区适配

第五阶段:上线发布

txt 复制代码
1. H5 部署到服务器
2. 微信小程序上传审核发布
3. Android APK/AAB 打包
4. iOS IPA 打包
5. 应用市场审核
6. 版本更新
7. 崩溃监控和错误上报

26. 资源文档链接大全

26.1 uni-app 官方资源

资源 链接 说明
uni-app 官网 https://uniapp.dcloud.net.cn/ 官方首页
uni-app 快速上手 https://uniapp.dcloud.net.cn/quickstart.html HBuilderX 创建、运行、发行
CLI 创建项目 https://uniapp.dcloud.net.cn/quickstart-cli.html 命令行创建和构建
pages.json 文档 https://uniapp.dcloud.net.cn/collocation/pages.html 页面、导航、tabBar、分包
manifest.json 文档 https://uniapp.dcloud.net.cn/collocation/manifest.html 应用名称、权限、平台配置
package.json 文档 https://uniapp.dcloud.net.cn/collocation/package.html scripts 和自定义平台
条件编译文档 https://uniapp.dcloud.io/platform 多端差异处理
组件文档 https://uniapp.dcloud.net.cn/component/ 内置组件、easycom
API 文档 https://uniapp.dcloud.net.cn/api/ 网络、路由、存储、媒体等
网络请求 uni.request https://uniapp.dcloud.net.cn/api/request/request.html 请求接口
路由 API https://uniapp.dcloud.net.cn/api/router.html navigateTo、switchTab 等
本地存储 API https://uniapp.dcloud.net.cn/api/storage/storage.html setStorage、getStorage
样式和 rpx https://uniapp.dcloud.net.cn/tutorial/syntax-css.html rpx、css、布局
插件市场 https://ext.dcloud.net.cn/ UI、插件、模板
HBuilderX 下载 https://www.dcloud.io/hbuilderx.html 官方开发工具
DCloud 开发者中心 https://dev.dcloud.net.cn/ AppID、证书、云服务

26.2 UI 组件库

资源 链接 说明
uni-ui https://uniapp.dcloud.net.cn/component/uniui/uni-ui.html DCloud 官方 UI
uView Plus https://uiadmin.net/uview-plus/ Vue3 版 uView
ThorUI https://thorui.cn/ 移动端 UI 组件
Wot Design Uni https://wot-design-uni.cn/ uni-app Vue3 组件库

26.3 小程序官方文档

平台 链接 说明
微信小程序文档 https://developers.weixin.qq.com/miniprogram/dev/framework/ 微信小程序开发
微信开发者工具 https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html 调试、预览、上传
微信公众平台 https://mp.weixin.qq.com/ 小程序后台
支付宝小程序文档 https://opendocs.alipay.com/mini/developer 支付宝小程序
抖音小程序文档 https://developer.open-douyin.com/docs/resource/zh-CN/mini-app/introduction/overview 抖音小程序
百度智能小程序 https://smartprogram.baidu.com/docs/introduction/enter_application/ 百度小程序
QQ 小程序 https://q.qq.com/wiki/ QQ 小程序

26.4 App 发布相关

资源 链接 说明
Apple Developer https://developer.apple.com/ 苹果开发者
App Store Connect https://appstoreconnect.apple.com/ iOS App 上架后台
App Store Connect 帮助 https://developer.apple.com/help/app-store-connect/ 官方上架文档
Google Play Console https://play.google.com/console Google Play 上架后台
Android Developers https://developer.android.com/ Android 官方文档
华为开发者联盟 https://developer.huawei.com/consumer/cn/ 华为应用市场
小米开放平台 https://dev.mi.com/ 小米应用商店
OPPO 开放平台 https://open.oppomobile.com/ OPPO 应用市场
vivo 开放平台 https://dev.vivo.com.cn/ vivo 应用市场
腾讯开放平台 https://open.qq.com/ 应用宝

26.5 前端基础资源

资源 链接 说明
Vue 官方文档 https://cn.vuejs.org/ Vue3 学习
TypeScript 文档 https://www.typescriptlang.org/zh/ TS 学习
Pinia 文档 https://pinia.vuejs.org/zh/ 状态管理
Vite 文档 https://cn.vitejs.dev/ 构建工具
MDN Web Docs https://developer.mozilla.org/zh-CN/ Web 基础
Can I Use https://caniuse.com/ CSS/JS 兼容性

27. 上线前检查清单

27.1 通用检查

txt 复制代码
□ 是否切换到生产环境接口
□ token 失效是否能自动跳登录
□ 请求失败是否有提示
□ loading 是否正常关闭
□ 页面是否有空白
□ 图片是否都能加载
□ 表单校验是否完整
□ 版本号是否递增
□ 是否删除 console 和测试入口
□ 是否处理弱网和超时
□ 是否有隐私政策
□ 是否测试 Android 和 iOS 真机

27.2 H5 检查

txt 复制代码
□ 域名是否配置 HTTPS
□ 路由刷新是否正常
□ 跨域是否解决
□ 静态资源是否加载成功
□ gzip 是否开启
□ 微信浏览器是否正常
□ 移动端适配是否正常

27.3 微信小程序检查

txt 复制代码
□ AppID 是否正确
□ request 合法域名是否配置
□ uploadFile/downloadFile 域名是否配置
□ 隐私协议是否配置
□ 权限说明是否配置
□ 分包体积是否合规
□ 真机预览是否正常
□ 审核账号是否可用
□ 支付、分享、订阅消息是否正常

27.4 App 检查

txt 复制代码
□ 应用图标是否正确
□ 启动图是否正确
□ 包名 / Bundle ID 是否正确
□ versionCode 是否递增
□ Android 签名是否正确
□ iOS 证书和描述文件是否正确
□ 权限申请是否合理
□ 隐私政策是否完整
□ 崩溃日志是否接入
□ 应用市场资料是否完整

总结

uni-app 的核心不是简单地"写一次,到处运行",而是:

txt 复制代码
统一业务代码
统一组件规范
统一请求封装
统一状态管理
统一路由封装
统一样式规范
通过条件编译和平台适配层处理差异
分别完成 H5、小程序、App 的配置和发布

你真正要掌握的重点是:

txt 复制代码
1. Vue3 + TypeScript 基础
2. pages.json 页面和路由配置
3. manifest.json 应用和平台配置
4. uni-app 内置组件和 API
5. request、router、storage 封装
6. Pinia 状态管理
7. rpx、flex、安全区适配
8. 条件编译
9. H5、小程序、App 三端差异
10. H5 部署、小程序审核、App 打包上架

建议最终做一个完整项目练习:

txt 复制代码
登录注册
首页轮播
商品分类
商品列表
商品详情
购物车
订单提交
个人中心
设置页面
H5 发布
微信小程序发布
Android App 打包
iOS App 打包

完整做完一遍,你就基本具备 uni-app 商业项目开发和上线能力。

相关推荐
weixin_lynhgworld1 小时前
品牌私域版|品牌专属盲盒小程序,沉淀私域用户、提升品牌溢价
小程序
搬砖的前端1 小时前
AI工具集:Git提交时使用AI进行CodeReview如何在前端应用构建NPM包
前端·人工智能·git·npm·codeview
Bigger2 小时前
mini-cc 终端 UI:用 React 写 CLI 是什么体验
前端·react.js·ai编程
于先生吖2 小时前
同城物流创业项目,Java源码搭建多车型搬家拉货、就近配货预约小程序
java·开发语言·小程序
在水一缸2 小时前
警惕供应链陷阱:从 Red Hat npm 恶意包事件看依赖安全防护
前端·安全·npm·供应链安全·red hat·恶意包·依赖安全
梦梦代码精2 小时前
TP8+Vue3+UniApp:LikeShop架构受青睐!
架构·uni-app
天下无贼!2 小时前
【功能实现】前端动态表单的实现原理与三种场景实战
前端
小雨下雨的雨2 小时前
鸿蒙PC用Electron框架 实现 房产交易系统核心算法深度解析
前端·javascript·算法·华为·electron·鸿蒙系统
snow@li2 小时前
前端:本地电脑和服务器,本质上都是一台计算机。
运维·服务器·前端