Featured image of post UniApp 跨端开发:Vue 语法一次编写,10+ 端发布

UniApp 跨端开发:Vue 语法一次编写,10+ 端发布

UniApp 是 DCloud 推出的「Vue 写多端」框架——一套代码同时发到 iOS / Android / 微信小程序 / 支付宝小程序 / 抖音小程序 / H5 / 各种快应用。本文从环境搭建、模板创建、目录结构,到条件编译、生命周期、跨端注意事项,串起完整开发流程。

为什么写这篇:UniApp 是国内"Vue 写多端"最成熟的方案——2023 年统计有 600 万+ 开发者。一个团队写一套 Vue 代码,就能发到微信小程序、抖音小程序、H5、iOS/Android——节省 60%+ 人力。本文从环境到实战完整走通。

适用读者:要快速开发多端小程序的前端;从 Vue 转 UniApp 的工程师;想了解跨端框架对比的负责人。

前置知识:Vue 2 基础;会用 Vue CLI。

目录

  1. UniApp 是什么
  2. 环境准备
  3. 创建项目
  4. 目录结构
  5. 条件编译:跨端兼容的关键
  6. UniApp 生命周期
  7. 页面与路由
  8. 常用 API:网络 / 存储 / 位置
  9. 跨端注意事项与坑
  10. UniApp vs Taro vs React Native vs Flutter

1. UniApp 是什么

DCloud 推出的"一次开发,多端发布"框架。Vue 语法 + 小程序能力 + H5/Web 能力——一套代码同时发布到:

支持度
iOS / Android(App)✅ 真机原生
H5✅ Web
微信小程序✅ 完整支持
支付宝小程序
百度小程序
抖音小程序
QQ 小程序
快应用
钉钉小程序
飞书小程序
各厂商快应用✅ 10+ 个

Why 选择 UniApp

  1. Vue 语法——学习成本低,国内前端主力栈
  2. 生态完整——uni-ui / uView UI / uni-ui-plus 等组件库丰富
  3. IDE 配套——HBuilderX(官方 IDE)开箱即用,无需配 Webpack/Vite
  4. 社区活跃——DCloud 论坛 + 大量 GitHub 仓库

2. 环境准备

2.1 推荐方式:HBuilderX(官方 IDE)

下载 HBuilderX——免费、可视化、内置模拟器。

优点:零配置、模板多、可视化运行、发布 缺点:基于 VSCode 内核改的,部分插件兼容性一般

2.2 命令行方式(适合习惯 Webpack/Vite 的工程师)

1
2
3
4
# 全局装 vue-cli
npm install -g @vue/cli

vue -V   # @vue/cli 5.0.x

版本要求(推荐):

工具版本
Node14.21.3(官方推荐)
npm6.14.18
yarn1.22.19
vue-cli5.0.8

Node 兼容性:UniApp 早期版本不兼容 Node 18+。用 nvm 切到 Node 14/16 是最稳的。


3. 创建项目

3.1 命令行(vue-cli)

1
vue create -p dcloudio/uni-preset-vue my-project

交互式:

1
2
? 请选择 uni-app 模板: hello uni-app   # 官方默认模板
? 是否使用 TypeScript: No                # 也可选 Yes

镜像加速vue create 拉模板可能慢——HBuilderX 内置模板不走这一步。

3.2 HBuilderX

文件 → 新建 → 项目 → uni-app → 选模板(默认 / Hello uni-app / 登录模板 / 地图模板 / 蓝牙模板…)。

3.3 运行

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 浏览器(H5)
npm run dev:h5

# 微信小程序(需配微信开发者工具路径)
npm run dev:mp-weixin

# 支付宝小程序
npm run dev:mp-alipay

# App(需配模拟器或真机)
npm run dev:app

4. 目录结构

 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
my-project/
├── pages/                      # 页面文件(自动注册路由)
│   ├── index/
│   │   └── index.vue
│   ├── about/
│   │   └── about.vue
│   └── list/
│       └── list.vue
├── static/                     # 静态资源(不会被编译)
│   ├── images/
│   └── icons/
├── components/                 # 自定义公共组件
│   └── my-card/
│       └── my-card.vue
├── common/                     # 公共 JS / CSS
│   ├── api.js
│   └── uni.css
├── store/                      # Vuex
│   └── index.js
├── utils/                      # 工具函数
│   └── request.js
├── App.vue                     # 应用配置(生命周期、全局样式)
├── main.js                     # 入口 JS
├── manifest.json               # 应用配置(appid、版本、权限)
├── pages.json                  # 页面路由 + tabBar + navigationBar
├── uni.scss                    # 全局 SCSS 变量
└── package.json

pages.json 是 UniApp 的"路由 + 导航 + tabBar"配置文件——比 Vue Router 简单。


5. 条件编译:跨端兼容的关键

UniApp 的杀手锏——用注释语法实现编译时的跨端代码分叉。

5.1 模板条件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<!-- #ifdef H5 -->
<view>这段只在 H5 显示</view>
<!-- #endif -->

<!-- #ifdef MP-WEIXIN -->
<view>只在微信小程序显示</view>
<!-- #endif -->

<!-- #ifdef APP-PLUS -->
<view>只在 App 端显示</view>
<!-- #endif -->

5.2 JS 条件

1
2
3
4
5
6
7
// #ifdef H5
console.log('H5 only')
// #endif

// #ifndef MP-WEIXIN
console.log('非微信端都执行')
// #endif

5.3 CSS 条件

1
2
3
4
5
6
7
/* #ifdef H5 */
.header { padding-top: 44px; }   /* H5 顶部避开浏览器栏 */
/* #endif */

/* #ifdef MP-WEIXIN */
.header { padding-top: 0; }
/* #endif */

5.4 常见条件编译关键字

关键字含义
H5H5 端
MP-WEIXIN微信小程序
MP-ALIPAY支付宝小程序
MP-BAIDU百度小程序
MP-TOUTIAO抖音/头条小程序
MP-QQQQ 小程序
MP所有小程序
APP-PLUSApp 端(iOS / Android)
APP-PLUS-NVUEApp nvue 页面(原生渲染)
APP-NVUE同上
APP-VUEApp 端 vue 页面

5.5 实战:H5 显示分享按钮 / 小程序隐藏

1
2
3
4
5
6
7
8
9
<view class="actions">
  <!-- #ifdef H5 -->
  <button @click="shareToWeibo">分享到微博</button>
  <!-- #endif -->

  <!-- #ifdef MP-WEIXIN -->
  <button open-type="share">微信分享</button>
  <!-- #endif -->
</view>

6. UniApp 生命周期

6.1 应用生命周期(App.vue)

钩子说明
onLaunch应用初始化(全局只触发一次)
onShow应用启动或从后台进入前台
onHide应用从前台进入后台
onError报错时触发
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// App.vue
export default {
  onLaunch() {
    console.log('App Launch')
  },
  onShow() {
    console.log('App Show')
  },
  onHide() {
    console.log('App Hide')
  }
}

6.2 页面生命周期

钩子说明
onLoad页面加载(接收 options 参数)
onShow页面显示
onReady页面初次渲染完成
onHide页面隐藏
onUnload页面卸载
onPullDownRefresh用户下拉刷新
onReachBottom页面上拉触底
onShareAppMessage微信分享
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
// pages/index/index.vue
export default {
  data() {
    return { count: 0 }
  },
  onLoad(options) {
    console.log('页面加载,参数:', options)
  },
  onShow() {
    console.log('页面显示')
  },
  onPullDownRefresh() {
    this.refresh()
  },
  methods: {
    refresh() {
      // 重新拉数据
      uni.stopPullDownRefresh()
    }
  }
}

vs Vue 生命周期:UniApp 用 onLoad / onShow 替代 Vue 的 mounted——因为 App 切后台再回来时,页面不一定重新加载。


7. 页面与路由

7.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
33
34
35
36
37
38
39
40
41
42
{
  "pages": [
    {
      "path": "pages/index/index",
      "style": {
        "navigationBarTitleText": "首页",
        "enablePullDownRefresh": true
      }
    },
    {
      "path": "pages/about/about",
      "style": {
        "navigationBarTitleText": "关于"
      }
    }
  ],
  "globalStyle": {
    "navigationBarTextStyle": "white",
    "navigationBarTitleText": "我的 App",
    "navigationBarBackgroundColor": "#42b883",
    "backgroundColor": "#f8f8f8"
  },
  "tabBar": {
    "color": "#7A7E83",
    "selectedColor": "#42b883",
    "backgroundColor": "#FFFFFF",
    "list": [
      {
        "pagePath": "pages/index/index",
        "text": "首页",
        "iconPath": "static/icons/home.png",
        "selectedIconPath": "static/icons/home-active.png"
      },
      {
        "pagePath": "pages/about/about",
        "text": "关于",
        "iconPath": "static/icons/user.png",
        "selectedIconPath": "static/icons/user-active.png"
      }
    ]
  }
}

7.2 路由 API

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// 跳转到新页面(保留当前页面)
uni.navigateTo({ url: '/pages/detail/detail?id=123' })

// 重定向(关闭当前页面,跳到新页面)
uni.redirectTo({ url: '/pages/login/login' })

// 切换 tabBar 页面
uni.switchTab({ url: '/pages/index/index' })

// 返回上一页(delta:返回层数)
uni.navigateBack({ delta: 1 })

// 关闭所有页面,打开到应用内的某个页面
uni.reLaunch({ url: '/pages/index/index' })

7.3 接收参数

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// 跳转
uni.navigateTo({ url: '/pages/detail/detail?id=123&name=test' })

// 接收(在 onLoad 钩子)
export default {
  onLoad(options) {
    console.log(options.id)    // '123'
    console.log(options.name)  // 'test'
  }
}

8. 常用 API:网络 / 存储 / 位置

8.1 网络请求

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
// 推荐封装
function request(url, method, data) {
  return new Promise((resolve, reject) => {
    uni.request({
      url: 'https://api.example.com' + url,
      method,
      data,
      header: {
        'Authorization': 'Bearer ' + uni.getStorageSync('token')
      },
      success: (res) => {
        if (res.statusCode === 200) resolve(res.data)
        else reject(res)
      },
      fail: (err) => reject(err)
    })
  })
}

// 用法
const data = await request('/user/profile', 'GET')

8.2 数据存储

1
2
3
4
5
6
7
8
// 同步
uni.setStorageSync('key', 'value')
uni.getStorageSync('key')          // 'value'
uni.removeStorageSync('key')

// 异步
await uni.setStorage({ key: 'k', data: 'v' })
const { data } = await uni.getStorage({ key: 'k' })

H5 端底层是 localStorage——大小限制 5-10MB

8.3 位置

1
2
3
4
5
6
7
uni.getLocation({
  type: 'gcj02',
  success: (res) => {
    console.log('纬度', res.latitude)
    console.log('经度', res.longitude)
  }
})

8.4 系统信息

1
2
3
4
const info = uni.getSystemInfoSync()
console.log(info.platform)      // 'ios' | 'android' | 'devtools'
console.log(info.screenWidth)
console.log(info.statusBarHeight)   // 状态栏高度

8.5 弹窗

1
2
3
4
uni.showToast({ title: '保存成功', icon: 'success' })
uni.showModal({ title: '提示', content: '确定删除?', success: (r) => {
  if (r.confirm) console.log('用户点了确定')
}})

9. 跨端注意事项与坑

9.1 v-if 替代 v-show

1
2
<!-- 小程序不支持 v-show(性能差),用 v-if -->
<view v-if="show">内容</view>

9.2 标签必须闭合

1
2
3
4
5
<!-- ❌ 自闭合 -->
<input ...>

<!-- ✅ 自闭合 -->
<input ... />

9.3 没有 <img> 标签

1
2
3
4
5
<!-- ❌ 用 img -->
<img src="..." />

<!-- ✅ 用 image -->
<image src="..." />

9.4 没有 <a> 标签

1
2
3
4
5
<!-- ❌ 用 a 标签跳转 -->
<a href="/about">关于</a>

<!-- ✅ 用 navigator 组件或 JS API -->
<navigator url="/pages/about/about">关于</navigator>

9.5 没有 <div>,用 <view>;没有 <span>,用 <text>

1
2
3
<view class="container">
  <text class="title">{{ msg }}</text>
</view>

9.6 CSS 单位用 rpx(响应式像素)

1
2
3
4
5
.container {
  width: 750rpx;     /* iPhone 6 下等于 375px,全屏 */
  padding: 20rpx;
  font-size: 28rpx;
}

rpx = 屏幕宽度的 1/750——所有设备按比例缩放。

9.7 小程序无法直接操作 DOM

1
2
3
4
5
// ❌ 错误
document.querySelector('.foo').classList.add('active')

// ✅ 正确:通过 Vue 响应式
this.isActive = true

9.8 微信小程序的登录流程

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
// 1. 调 wx.login() 拿 code
uni.login({
  provider: 'weixin',
  success: (loginRes) => {
    const code = loginRes.code
    // 2. 把 code 发到自家后端,换 session_key + openid
    uni.request({
      url: 'https://api.example.com/wechat/login',
      method: 'POST',
      data: { code },
      success: (res) => {
        uni.setStorageSync('token', res.data.token)
      }
    })
  }
})

10. UniApp vs Taro vs React Native vs Flutter

维度UniAppTaro 3React NativeFlutter
语法Vue 2/3ReactReactDart
渲染WebView / 小程序WebView / 小程序 / RNNative自绘引擎
性能中(WebView 限制)接近原生最优
多端覆盖10+ 端8 端仅 iOS/Android仅 iOS/Android
学习成本低(Vue)中(React + Taro API)高(Dart)
生态国内最丰富中(京东系)Facebook 系Google 系
包体积1-3MB1-3MB5-10MB5-15MB
TypeScript支持支持
大厂使用阿里、京东、字节、腾讯京东、网易、美团Facebook、AirbnbGoogle、阿里

选型建议

  • 国内小程序 + H5 + App 全部都要UniApp(首选)
  • 团队熟悉 React + 多端 → Taro 3
  • 追求 iOS/Android 性能 + 团队有原生经验 → React Native
  • 极致性能 + 复杂动画 + 跨端 UI 一致 → Flutter
  • 只需要 H5 / Web → 直接 Vue/React + Vite,不要用跨端框架

小结

UniApp 入门核心:

  1. 环境:HBuilderX(IDE) 或 vue-cli(命令行)
  2. 创建vue create -p dcloudio/uni-preset-vue 选 hello uni-app 模板
  3. 路由:pages.json(不是 Vue Router)
  4. 跨端:条件编译 <!-- #ifdef MP-WEIXIN --> 是关键
  5. API:全部走 uni.xxx 命名空间(uni.request / uni.navigateTo / uni.getLocation)
  6. :无 DOM、无 a/div/img、必须用 view/text/image、CSS 用 rpx

下一步:学 uni-ui 组件库(官方)、uView UI(社区最流行)、uCharts(图表)、即时通讯(融云 / 环信 UniApp SDK)、App 上架(iOS App Store + 安卓各大市场)。

参考资料

使用 Hugo 构建
主题 StackJimmy 设计