前言

在移动互联网多端化的今天,一款产品往往需要同时覆盖微信小程序、支付宝小程序、抖音小程序、H5、iOS App、Android App,甚至鸿蒙应用。如果为每个平台单独开发一套代码,不仅开发成本高昂,后期维护更是噩梦。

UniApp 正是为解决这一痛点而生的跨端开发框架。它基于 Vue.js 技术栈,遵循 "一次编码,多端运行" 的理念,开发者只需编写一套代码,即可编译发布到 iOS、Android、H5、以及各种小程序(微信 / 支付宝 / 百度 / 抖音 / 飞书 / QQ / 快手)等多个平台。截至 2026 年,UniApp 生态已覆盖数百万应用,月活设备超 12 亿,成为国内跨端开发的事实标准uni-app。

本文将从基础概念出发,逐步深入到企业级开发实战,涵盖环境搭建、核心语法、条件编译、网络封装、状态管理、性能优化等全链路知识点,并配套大量可直接复用的代码示例,帮助读者系统性掌握 UniApp 开发能力。


一、环境搭建与项目初始化

1.1 开发工具选择

UniApp 官方推荐使用 HBuilderX 作为主力开发 IDE,它内置了完整的编译、运行、打包能力,对 App 端原生调试和云打包支持最为完善。对于习惯 VSCode 的开发者,也可以通过 unibest 等脚手架实现 VSCode 开发环境搭建。

两种开发方案对比:

表格

方案 优势 适用场景
HBuilderX 官方原生支持、真机调试便捷、云打包开箱即用、NVUE 支持完善 全平台开发、App 端为主
VSCode + unibest 插件生态丰富、TS 支持更好、Vite 构建速度快 H5 + 小程序为主、前端团队协作

对于初学者,建议直接使用 HBuilderX,减少环境配置成本。

1.2 项目创建步骤

  1. 下载安装 HBuilderX 正式版
  2. 文件 → 新建 → 项目 → 选择 uni-app 类型
  3. 填写项目名称,选择 Vue3 版本模板(推荐)
  4. 点击创建,等待项目初始化完成

1.3 运行与调试

创建完成后,点击顶部工具栏的「运行」按钮,可选择运行到不同平台:

  • 运行到浏览器:H5 调试
  • 运行到小程序模拟器:微信 / 支付宝等小程序调试
  • 运行到手机或模拟器:App 端真机调试

二、项目目录结构与工程化规范

一个规范的 UniApp 项目目录结构如下:

plaintext

┌─ uni_modules          // 插件模块目录(uni_modules规范)
├─ pages                // 页面目录
│  └─ index
│     └─ index.vue      // 首页
├─ static               // 静态资源(图片、字体等)
├─ utils                // 工具函数
├─ api                  // 接口请求
├─ stores               // Pinia 状态管理
├─ components           // 公共组件
├─ common               // 公共样式、常量
├─ App.vue              // 应用入口
├─ main.js              // 主入口文件
├─ pages.json           // 页面路由与全局配置
└─ manifest.json        // 应用配置与各平台参数

2.1 核心配置文件详解

pages.json 是 UniApp 最重要的配置文件,负责页面路由、导航栏、TabBar、窗口样式等全局配置。

json

{
  "pages": [
    {
      "path": "pages/index/index",
      "style": {
        "navigationBarTitleText": "首页",
        "navigationBarBackgroundColor": "#ffffff",
        "navigationBarTextStyle": "black",
        "enablePullDownRefresh": true
      }
    }
  ],
  "globalStyle": {
    "navigationBarTextStyle": "black",
    "navigationBarTitleText": "UniApp实战",
    "navigationBarBackgroundColor": "#ffffff",
    "backgroundColor": "#f5f5f5"
  },
  "tabBar": {
    "color": "#999999",
    "selectedColor": "#007aff",
    "backgroundColor": "#ffffff",
    "list": [
      {
        "pagePath": "pages/index/index",
        "text": "首页",
        "iconPath": "static/tab/home.png",
        "selectedIconPath": "static/tab/home-active.png"
      },
      {
        "pagePath": "pages/mine/mine",
        "text": "我的",
        "iconPath": "static/tab/mine.png",
        "selectedIconPath": "static/tab/mine-active.png"
      }
    ]
  }
}

manifest.json 用于配置应用 ID、版本号、各平台专属参数(如小程序 AppID、App 权限声明等)。


三、核心语法与 Vue3 适配详解

UniApp 基于 Vue 语法,但受限于小程序平台的双线程架构,并非所有 Web 端 Vue 特性都能完全支持。

3.1 模板语法

UniApp 的模板语法与 Vue 基本一致,但需要注意:不能使用 HTML 标签,必须使用 UniApp 内置组件

html

预览

<template>
  <view class="container">
    <!-- 文本显示 -->
    <text class="title">{{ title }}</text>
    
    <!-- 列表渲染 -->
    <view v-for="item in list" :key="item.id" class="list-item">
      <image :src="item.cover" mode="aspectFill" class="cover" />
      <text class="name">{{ item.name }}</text>
    </view>
    
    <!-- 条件渲染 -->
    <view v-if="loading" class="loading">加载中...</view>
    <view v-else class="content">
      <button @click="handleClick" type="primary">点击按钮</button>
    </view>
  </view>
</template>

常用组件对应关系:

  • divview
  • span / ptext
  • imgimage
  • anavigator
  • inputinput / textarea

3.2 Script 语法(Vue3 Composition API)

UniApp 完全支持 Vue3 的 Composition API 和 <script setup> 语法,这也是当前推荐的开发方式。

html

预览

<script setup>
import { ref, reactive, computed, onMounted } from 'vue'

// 响应式数据
const title = ref('UniApp 实战教程')
const loading = ref(false)
const list = ref([])

// 计算属性
const count = computed(() => list.value.length)

// 方法
const handleClick = () => {
  uni.showToast({
    title: '点击成功',
    icon: 'success'
  })
}

// 获取数据
const fetchData = async () => {
  loading.value = true
  try {
    // 模拟接口请求
    await new Promise(resolve => setTimeout(resolve, 1000))
    list.value = [
      { id: 1, name: '商品A', cover: '/static/demo1.jpg' },
      { id: 2, name: '商品B', cover: '/static/demo2.jpg' }
    ]
  } finally {
    loading.value = false
  }
}

// 生命周期
onMounted(() => {
  fetchData()
})
</script>

3.3 样式语法

UniApp 支持 CSS、SCSS、Less 等预处理器,并提供了 rpx 响应式像素单位。

rpx 单位原理: 以 750px 宽的设计稿为基准,1rpx = 0.5px = 1 物理像素。在不同屏幕宽度下自动等比缩放。

scss

<style lang="scss" scoped>
.container {
  padding: 30rpx;
  background-color: #f5f5f5;
  min-height: 100vh;
  
  .title {
    font-size: 36rpx;
    font-weight: bold;
    color: #333;
    margin-bottom: 30rpx;
  }
  
  .list-item {
    display: flex;
    padding: 20rpx;
    background: #fff;
    border-radius: 16rpx;
    margin-bottom: 20rpx;
    
    .cover {
      width: 120rpx;
      height: 120rpx;
      border-radius: 8rpx;
      margin-right: 20rpx;
    }
    
    .name {
      flex: 1;
      font-size: 28rpx;
      color: #333;
    }
  }
}
</style>

注意: 小程序端不支持 * 选择器、通配符,部分高级 CSS 选择器也有限制,建议使用类选择器为主。


四、页面路由与生命周期

4.1 页面跳转

UniApp 提供了统一的路由 API,替代 Vue Router:

javascript

运行

// 保留当前页面,跳转到应用内的某个页面(可返回)
uni.navigateTo({
  url: '/pages/detail/detail?id=123'
})

// 关闭当前页面,跳转到应用内的某个页面
uni.redirectTo({
  url: '/pages/login/login'
})

// 跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面
uni.switchTab({
  url: '/pages/index/index'
})

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

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

4.2 页面参数接收

javascript

运行

// 方式一:onLoad 生命周期(推荐)
onLoad((options) => {
  console.log('页面参数:', options.id)
})

// 方式二:通过页面实例获取
import { getCurrentInstance } from 'vue'
const instance = getCurrentInstance()
const options = instance.proxy.$options

4.3 完整生命周期体系

UniApp 的生命周期分为应用生命周期页面生命周期两类:

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

  • onLaunch:应用初始化完成时触发(全局只触发一次)
  • onShow:应用从后台进入前台显示
  • onHide:应用从前台进入后台
  • onError:应用发生脚本错误或 API 调用失败

页面生命周期:

  • onLoad:页面加载,可获取参数
  • onShow:页面显示
  • onReady:页面初次渲染完成
  • onHide:页面隐藏
  • onUnload:页面卸载
  • onPullDownRefresh:下拉刷新
  • onReachBottom:上拉触底
  • onShareAppMessage:用户点击分享
  • onPageScroll:页面滚动

五、跨端适配核心:条件编译深度解析

条件编译是 UniApp 最核心的跨端能力,通过特殊的注释标记,在编译阶段根据目标平台自动包含或排除代码块,实现零运行时损耗的差异化适配uni-app。

5.1 基础语法

javascript

运行

// #ifdef 平台标识
仅在指定平台编译的代码
// #endif

// #ifndef 平台标识
除指定平台外都编译的代码
// #endif

// #ifdef 平台A || 平台B
多个平台满足其一即编译
// #endif

5.2 常用平台标识

表格

标识 对应平台
APP-PLUS App 端(iOS/Android)
H5 H5 网页端
MP-WEIXIN 微信小程序
MP-ALIPAY 支付宝小程序
MP-DOUYIN 抖音小程序
MP 所有小程序
HARMONY 鸿蒙应用

5.3 三大场景实战

场景一:模板层差异化组件

html

预览

<template>
  <view class="login-btn">
    <!-- #ifdef MP-WEIXIN -->
    <button open-type="getUserInfo" @getuserinfo="wxLogin">
      微信一键登录
    </button>
    <!-- #endif -->
    
    <!-- #ifdef APP-PLUS -->
    <button @click="appLogin">
      手机号快捷登录
    </button>
    <!-- #endif -->
    
    <!-- #ifdef H5 -->
    <button @click="h5Login">
      账号密码登录
    </button>
    <!-- #endif -->
  </view>
</template>

场景二:JS 逻辑层差异化 API

javascript

运行

// 统一封装登录接口
export const login = () => {
  // #ifdef MP-WEIXIN
  return new Promise((resolve, reject) => {
    uni.login({
      provider: 'weixin',
      success: resolve,
      fail: reject
    })
  })
  // #endif
  
  // #ifdef APP-PLUS
  return new Promise((resolve, reject) => {
    plus.oauth.getServices((services) => {
      const weixinService = services.find(s => s.id === 'weixin')
      weixinService.login(resolve, reject)
    }, reject)
  })
  // #endif
  
  // #ifdef H5
  return Promise.reject(new Error('H5端请使用账号密码登录'))
  // #endif
}

场景三:样式层差异化表现

scss

.page-container {
  padding-top: 20px;
  
  /* #ifdef MP-WEIXIN */
  padding-top: calc(20px + env(safe-area-inset-top));
  /* #endif */
  
  /* #ifdef APP-PLUS */
  padding-top: 44px;
  /* #endif */
}

5.4 工程化最佳实践

推荐采用 "三层架构" 组织条件编译代码,避免散落在业务各处:

plaintext

├─ platform
│  ├─ weixin       // 微信小程序专属
│  │  ├─ login.js
│  │  └─ pay.js
│  ├─ app          // App端专属
│  │  ├─ login.js
│  │  └─ pay.js
│  └─ index.js     // 统一出口

javascript

运行

// platform/index.js
// #ifdef MP-WEIXIN
import * as platformApi from './weixin'
// #endif
// #ifdef APP-PLUS
import * as platformApi from './app'
// #endif
// #ifdef H5
import * as platformApi from './h5'
// #endif

export default platformApi

这种方式让业务代码完全感知不到平台差异,所有差异化逻辑都收敛在 platform 层,极大提升了代码可维护性。


六、网络请求企业级封装方案

原生 uni.request 功能较为基础,企业级项目需要统一封装请求拦截、响应拦截、错误处理、Token 管理等能力。

6.1 基础封装实现

utils/request.js 中创建请求实例:

javascript

运行

// 环境配置
const BASE_CONFIG = {
  development: {
    baseUrl: 'http://localhost:3000/api',
    timeout: 15000
  },
  production: {
    baseUrl: 'https://api.example.com',
    timeout: 10000
  }
}

const env = process.env.NODE_ENV || 'development'
const config = BASE_CONFIG[env]

// 请求队列管理
let requestCount = 0
const showLoading = () => {
  if (requestCount === 0) {
    uni.showLoading({ title: '加载中', mask: true })
  }
  requestCount++
}

const hideLoading = () => {
  requestCount--
  if (requestCount <= 0) {
    uni.hideLoading()
    requestCount = 0
  }
}

// 核心请求方法
const request = (options) => {
  const { 
    url, 
    method = 'GET', 
    data = {}, 
    header = {},
    showLoading: needLoading = true 
  } = options
  
  needLoading && showLoading()
  
  // Token注入
  const token = uni.getStorageSync('token')
  if (token) {
    header['Authorization'] = `Bearer ${token}`
  }
  
  return new Promise((resolve, reject) => {
    uni.request({
      url: config.baseUrl + url,
      method,
      data,
      header: {
        'Content-Type': 'application/json',
        ...header
      },
      timeout: config.timeout,
      success: (res) => {
        const { statusCode, data: responseData } = res
        
        // HTTP 状态码处理
        if (statusCode >= 200 && statusCode < 300) {
          // 业务状态码处理
          if (responseData.code === 0) {
            resolve(responseData.data)
          } else if (responseData.code === 401) {
            // Token失效处理
            uni.removeStorageSync('token')
            uni.redirectTo({ url: '/pages/login/login' })
            reject(new Error('登录已过期'))
          } else {
            uni.showToast({
              title: responseData.message || '请求失败',
              icon: 'none'
            })
            reject(responseData)
          }
        } else {
          uni.showToast({
            title: `网络错误 ${statusCode}`,
            icon: 'none'
          })
          reject(res)
        }
      },
      fail: (err) => {
        uni.showToast({
          title: '网络连接失败,请检查网络',
          icon: 'none'
        })
        reject(err)
      },
      complete: () => {
        needLoading && hideLoading()
      }
    })
  })
}

// 快捷方法
export const get = (url, data, options = {}) => 
  request({ url, method: 'GET', data, ...options })

export const post = (url, data, options = {}) => 
  request({ url, method: 'POST', data, ...options })

export const put = (url, data, options = {}) => 
  request({ url, method: 'PUT', data, ...options })

export const del = (url, data, options = {}) => 
  request({ url, method: 'DELETE', data, ...options })

export default request

6.2 API 模块化管理

api 目录下按业务模块组织接口:

javascript

运行

// api/user.js
import { get, post } from '@/utils/request'

// 获取用户信息
export const getUserInfo = () => get('/user/info')

// 更新用户资料
export const updateUser = (data) => post('/user/update', data)

// 登录
export const login = (data) => post('/auth/login', data)

业务页面中使用:

javascript

运行

import { getUserInfo, updateUser } from '@/api/user'

const fetchUserInfo = async () => {
  try {
    const data = await getUserInfo()
    console.log('用户信息:', data)
  } catch (err) {
    console.error('获取失败:', err)
  }
}

6.3 跨端兼容处理

不同平台对请求的支持存在差异,需要在请求封装中做兼容:

javascript

运行

// 小程序端 PUT/DELETE 方法兼容性处理
// #ifdef MP
if (method === 'PUT' || method === 'DELETE') {
  data._method = method
  method = 'POST'
}
// #endif

// H5端跨域凭证
// #ifdef H5
config.withCredentials = true
// #endif

// App端SSL证书校验
// #ifdef APP-PLUS
config.sslVerify = env === 'production'
// #endif

七、状态管理:Pinia 最佳实践

Vue3 生态中,Pinia 已取代 Vuex 成为官方推荐的状态管理方案。UniApp 中使用 Pinia 需要解决持久化兼容问题。

7.1 Pinia 集成步骤

1. 安装依赖

bash

运行

npm install pinia pinia-plugin-persistedstate

2. 配置入口

javascript

运行

// main.js
import { createSSRApp } from 'vue'
import { createPinia } from 'pinia'
import persist from 'pinia-plugin-persistedstate'
import App from './App.vue'

export function createApp() {
  const app = createSSRApp(App)
  const pinia = createPinia()
  
  // 适配小程序端持久化
  pinia.use(({ store }) => {
    store.$persist = (options = {}) => {
      const { key = store.$id, paths = [] } = options
      
      // 初始化时从 storage 读取
      const saved = uni.getStorageSync(key)
      if (saved) {
        store.$patch(saved)
      }
      
      // 状态变化时写入 storage
      store.$subscribe((_, state) => {
        const toSave = paths.length 
          ? Object.fromEntries(paths.map(p => [p, state[p]]))
          : state
        uni.setStorageSync(key, toSave)
      })
    }
  })
  
  app.use(pinia)
  return { app }
}

7.2 用户状态模块实战

javascript

运行

// stores/user.js
import { defineStore } from 'pinia'

export const useUserStore = defineStore('user', {
  state: () => ({
    token: '',
    userInfo: null,
    loginTime: null
  }),
  
  getters: {
    isLogin: (state) => !!state.token,
    userId: (state) => state.userInfo?.id,
    nickname: (state) => state.userInfo?.nickname || '未登录'
  },
  
  actions: {
    // 设置登录态
    setLogin(token, userInfo) {
      this.token = token
      this.userInfo = userInfo
      this.loginTime = Date.now()
      uni.setStorageSync('token', token)
    },
    
    // 更新用户信息
    updateUserInfo(info) {
      this.userInfo = { ...this.userInfo, ...info }
    },
    
    // 退出登录
    logout() {
      this.token = ''
      this.userInfo = null
      this.loginTime = null
      uni.removeStorageSync('token')
      uni.reLaunch({ url: '/pages/login/login' })
    }
  },
  
  // 持久化配置
  persist: {
    key: 'user-store',
    paths: ['token', 'userInfo']
  }
})

7.3 购物车状态模块示例

javascript

运行

// stores/cart.js
import { defineStore } from 'pinia'

export const useCartStore = defineStore('cart', {
  state: () => ({
    items: []
  }),
  
  getters: {
    // 商品总数
    totalCount: (state) => 
      state.items.reduce((sum, item) => sum + item.quantity, 0),
    
    // 总价
    totalPrice: (state) => 
      state.items.reduce((sum, item) => sum + item.price * item.quantity, 0),
    
    // 已选中商品
    selectedItems: (state) => 
      state.items.filter(item => item.selected),
    
    // 选中总价
    selectedPrice: (state) => 
      this.selectedItems.reduce((sum, item) => sum + item.price * item.quantity, 0)
  },
  
  actions: {
    // 添加商品
    addItem(product) {
      const existing = this.items.find(item => item.id === product.id)
      if (existing) {
        existing.quantity += 1
      } else {
        this.items.push({ ...product, quantity: 1, selected: true })
      }
    },
    
    // 减少商品
    decreaseItem(productId) {
      const item = this.items.find(i => i.id === productId)
      if (item) {
        if (item.quantity > 1) {
          item.quantity -= 1
        } else {
          this.removeItem(productId)
        }
      }
    },
    
    // 删除商品
    removeItem(productId) {
      this.items = this.items.filter(item => item.id !== productId)
    },
    
    // 清空购物车
    clearCart() {
      this.items = []
    },
    
    // 全选/取消全选
    toggleAll(selected) {
      this.items.forEach(item => {
        item.selected = selected
      })
    }
  },
  
  persist: {
    key: 'cart-store'
  }
})

7.4 组件中使用

javascript

运行

import { useUserStore } from '@/stores/user'
import { useCartStore } from '@/stores/cart'

const userStore = useUserStore()
const cartStore = useCartStore()

// 读取状态
console.log('是否登录:', userStore.isLogin)
console.log('购物车数量:', cartStore.totalCount)

// 调用方法
userStore.setLogin(token, userInfo)
cartStore.addItem(product)

八、样式适配与多端布局一致性

8.1 尺寸单位选型

UniApp 提供了多种尺寸单位,各有适用场景:

表格

单位 特点 适用场景
rpx 响应式像素,750rpx = 屏幕宽 大部分布局、间距
px 固定像素 边框、细线
% 百分比 宽度比例
vh/vw 视口单位 全屏布局

最佳实践:

  • 布局间距、字体大小使用 rpx
  • 1px 边框使用 px 保证精细度
  • 高度不建议用 rpx,优先使用 flex 布局

8.2 安全区域适配

全面屏时代,刘海屏、底部小黑条是适配重灾区:

scss

/* 顶部安全区域 */
.safe-area-top {
  /* #ifdef MP-WEIXIN */
  padding-top: env(safe-area-inset-top);
  /* #endif */
  
  /* #ifdef APP-PLUS */
  padding-top: var(--status-bar-height);
  /* #endif */
}

/* 底部安全区域 */
.safe-area-bottom {
  padding-bottom: env(safe-area-inset-bottom);
}

/* 底部TabBar适配 */
.tab-bar {
  height: calc(100rpx + env(safe-area-inset-bottom));
  padding-bottom: env(safe-area-inset-bottom);
}

8.3 全局样式规范

建议建立统一的样式变量体系:

scss

/* common/variables.scss */
$primary-color: #007aff;
$success-color: #07c160;
$warning-color: #ff976a;
$danger-color: #ee0a24;

$text-primary: #333333;
$text-secondary: #666666;
$text-placeholder: #999999;

$bg-page: #f5f5f5;
$bg-card: #ffffff;

$border-color: #ebedf0;

$spacing-xs: 10rpx;
$spacing-sm: 20rpx;
$spacing-md: 30rpx;
$spacing-lg: 40rpx;

$radius-sm: 8rpx;
$radius-md: 16rpx;
$radius-lg: 24rpx;

九、性能优化全攻略

9.1 包体积优化

小程序端包体积优化:

  1. 分包加载:将非首屏页面放入分包,主包只保留 TabBar 页面和公共资源
  2. 图片压缩:静态图片压缩后上传 CDN,减少本地资源
  3. 按需引入:组件和工具函数按需引入,避免全量打包
  4. 移除无用代码:定期清理废弃页面和组件

json

// pages.json 分包配置
{
  "pages": [
    "pages/index/index",
    "pages/mine/mine"
  ],
  "subPackages": [
    {
      "root": "pages/goods",
      "pages": [
        "list",
        "detail",
        "category"
      ]
    },
    {
      "root": "pages/order",
      "pages": [
        "list",
        "detail",
        "confirm"
      ]
    }
  ],
  "preloadRule": {
    "pages/index/index": {
      "network": "wifi",
      "packages": ["pages/goods"]
    }
  }
}

9.2 渲染性能优化

  1. 减少 setData 调用频次:批量更新数据,避免频繁修改 data
  2. 长列表优化:使用 <scroll-view> + 虚拟列表,或 recycle-view 组件
  3. 图片懒加载<image lazy-load> 开启懒加载
  4. 避免频繁重排:减少动态修改样式,优先使用 class 切换

html

预览

<!-- 长列表优化示例 -->
<scroll-view scroll-y class="list-container">
  <view 
    v-for="(item, index) in visibleList" 
    :key="item.id"
    class="list-item"
  >
    <!-- 列表项内容 -->
  </view>
</scroll-view>

9.3 App 端原生渲染优化

对于 App 端性能要求高的页面,可以使用 nvue(原生渲染)方案,性能较 WebView 提升 50% 以上。

nvue 使用 Weex 渲染引擎,直接调用原生组件渲染,不依赖 WebView。但需要注意:

  • 仅支持 flex 布局
  • CSS 支持度有限
  • 写法与 vue 略有差异

9.4 启动速度优化

  1. 首屏直出:关键数据本地缓存,优先展示缓存数据
  2. 延迟加载:非首屏组件使用 v-if 延迟渲染
  3. 骨架屏:加载过程展示骨架屏,感知性能提升
  4. 预加载:TabBar 页面预加载下一页数据

十、原生能力调用与插件集成

10.1 常用原生 API

UniApp 封装了大量系统级 API,可直接调用:

javascript

运行

// 获取系统信息
const sysInfo = uni.getSystemInfoSync()
console.log('屏幕宽度:', sysInfo.screenWidth)
console.log('状态栏高度:', sysInfo.statusBarHeight)

// 扫码
uni.scanCode({
  success: (res) => {
    console.log('扫码结果:', res.result)
  }
})

// 拍照/选图
uni.chooseImage({
  count: 9,
  sizeType: ['compressed'],
  sourceType: ['album', 'camera'],
  success: (res) => {
    console.log('图片路径:', res.tempFilePaths)
  }
})

// 地理位置
uni.getLocation({
  type: 'gcj02',
  success: (res) => {
    console.log('经纬度:', res.latitude, res.longitude)
  }
})

10.2 插件市场生态

DCloud 插件市场提供数千款现成插件,涵盖支付、分享、推送、地图等常用能力。常用插件推荐:

  • uView Plus:全面的 UI 组件库
  • z-paging:下拉刷新 / 上拉加载组件
  • uni-pay:多端支付统一封装
  • uni-push:消息推送服务

10.3 自定义原生插件

对于 UniApp 未封装的原生能力,可以开发原生插件扩展。App 端支持原生 SDK 集成,通过 JSBridge 与前端通信。


十一、打包发布与多端部署

11.1 H5 端发布

HBuilderX 中选择「发行」→「网站 - PC Web 或手机 H5」,打包后生成 dist 目录,部署到 Nginx 或静态服务器即可。

Nginx 配置参考:

nginx

server {
    listen 80;
    server_name m.example.com;
    root /var/www/uniapp-h5;
    index index.html;
    
    location / {
        try_files $uri $uri/ /index.html;
    }
    
    location /static {
        expires 7d;
    }
}

11.2 小程序发布

  1. 配置 manifest.json 中的小程序 AppID
  2. 「发行」→「小程序 - 微信」,自动打开微信开发者工具
  3. 在开发者工具中点击上传,提交审核

11.3 App 端打包

云打包(推荐新手使用):

  • 「发行」→「原生 App - 云打包」
  • 填写证书、包名等信息
  • 等待云端打包完成,下载安装包

离线打包

  • 下载 App 离线 SDK
  • 使用 Android Studio / Xcode 本地编译
  • 适合需要深度定制原生能力的项目

十二、常见踩坑与解决方案

12.1 样式兼容类

问题: H5 端样式正常,小程序端样式错乱

解决方案:

  • 小程序不支持通配符选择器 *
  • 不支持后代选择器跨组件穿透(需用 /deep/::v-deep
  • 伪元素 ::before / ::after 仅部分组件支持
  • 避免使用 position: fixed,小程序端表现异常

12.2 数据更新类

问题: 修改数据后视图不更新

解决方案:

  • 对象新增属性使用 Vue.set 或解构赋值
  • 数组修改索引不触发响应式,用 splice 方法
  • 避免层级过深的数据结构,减少 diff 压力

12.3 生命周期类

问题: onLoad 只执行一次,返回页面不刷新

解决方案:

  • 需要每次显示都刷新的数据放在 onShow 中获取
  • 使用事件总线或 Pinia 状态同步
  • 返回页面传参使用 eventChannel 或全局状态

12.4 跨域问题

问题: H5 端接口跨域,小程序正常

解决方案:

  • 开发环境配置 manifest.json 的 devServer 代理
  • 生产环境后端配置 CORS 或 Nginx 反向代理
  • 小程序不存在跨域限制,需在后台配置 request 合法域名

十三、学习路线与进阶方向

13.1 新手学习路径

  1. 基础阶段:掌握 Vue3 语法、UniApp 核心组件、常用 API
  2. 进阶阶段:条件编译、网络封装、状态管理、组件封装
  3. 高级阶段:性能优化、原生插件、工程化、多端调试
  4. 专家阶段:源码原理、NVUE 渲染、架构设计、团队规范

13.2 技术演进方向

随着 uni-app x 的发布,UniApp 正在向全平台原生编译演进,支持编译为鸿蒙 ArkTS、Android Kotlin、iOS Swift 等原生代码,彻底摆脱 WebView 性能瓶颈,这也是未来的重要发展方向。


总结

UniApp 作为国内最成熟的跨端开发方案,在开发效率、生态完善度、性能表现之间取得了出色的平衡。掌握 UniApp 开发,意味着一套技术栈即可覆盖几乎所有移动端场景,极大提升个人技术价值和团队研发效率。

本文从基础到进阶,系统梳理了 UniApp 开发的核心知识点和最佳实践,并提供了大量可直接复用的代码模板。但技术学习贵在实践,建议读者结合实际项目,在开发中不断踩坑、总结,逐步形成自己的技术体系。

Logo

一站式 AI 云服务平台

更多推荐