一、概念简介
1.1 基本语言和开发规范
uni-app代码编写,基本语言包括js、vue、css。以及ts、scss等css预编译器。
在app端,还支持原生渲染的nvue,以及可以编译为kotlin和swift的uts。
为了实现多端兼容,综合考虑编译速度、运行性能等因素,uni-app 约定了如下开发规范:
每个页面是一个.vue文件- 组件标签靠近小程序规范,详见uni-app 组件规范
- 接口能力(JS API)靠近
小程序规范,但需将前缀wx、my等替换为uni,详见uni-app接口规范 - 数据绑定及事件处理同
Vue.js规范,同时补充了应用生命周期及页面的生命周期 - 如需兼容app-nvue平台,建议使用
flex布局进行开发
uni-app分编译器和运行时(runtime)。uni-app能实现一套代码、多端运行,是通过这2部分配合完成的。
1.2 编译器
-
编译器运行在电脑开发环境。一般是
内置在HBuilderX工具中,也可以使用独立的cli版。 -
开发者按uni-app规范编写代码,由编译器将开发者的代码编译生成每个平台支持的特有代码
- 在web平台,将.vue文件编译为js代码。与普通的vue cli项目类似
- 在微信小程序平台,编译器将.vue文件拆分生成wxml、wxss、js等代码
- 在app平台,将.vue文件编译为js代码。进一步,如果涉及uts代码:
- 在Android平台,将.uts文件编译为kotlin代码
- 在iOS平台,将.uts文件编译为swift代码
-
编译器分vue2版和vue3版
- vue2版:基于
webpack实现 - vue3版:基于
Vite实现,性能更快
- vue2版:基于
-
编译器支持条件编译,即可以指定某部分代码只编译到特定的终端平台。从而将公用和个性化融合在一个工程中。
js// #ifdef App console.log("这段代码只有在App平台才会被编译进去。非App平台编译后没有这段代码") // #endif
1.3 运行时
runtime不是运行在电脑开发环境,而是运行在真正的终端上。
uni-app在每个平台(Web、Android App、iOS App、各家小程序)都有各自的runtime。这是一个比较庞大的工程。
- 在小程序端,uni-app的runtime,主要是一个小程序版的vue runtime,页面路由、组件、api等方面基本都是转义。
- 在web端,uni-app的runtime相比普通的vue项目,多了一套ui库、页面路由框架、和uni对象(即常见API封装)
- 在App端,uni-app的runtime更复杂,可以先简单理解为DCloud也有一套小程序引擎,打包app时将开发者的代码和DCloud的小程序打包成了apk或ipa。当然,事实上DCloud确实有小程序引擎产品,供原生应用实现小程序化,详见
二、工程
一个 uni-app 工程,就是一个 Vue 项目,你可以通过 HBuilderX 或 cli 方式快速创建 uni-app 工程。
目录结构
shell
┌─uniCloud 云空间目录,支付宝小程序云为uniCloud-alipay,阿里云为uniCloud-aliyun,腾讯云为uniCloud-tcb(不重要)
│─components 符合vue组件规范的uni-app组件目录
│ └─comp-a.vue 可复用的a组件
├─utssdk 存放uts文件(已废弃)
├─pages 业务页面文件存放的目录
│ ├─index
│ │ └─index.vue index页面
│ └─list
│ └─list.vue list页面
├─static 存放应用引用的本地静态资源(如图片、视频等)的目录,注意:静态资源都应存放于此目录
├─uni_modules 存放uni_module 详见
├─platforms 存放各平台专用页面的目录,(不重要)
├─nativeplugins App原生语言插件 (不重要)
├─nativeResources App端原生资源目录(不重要)
│ ├─android Android原生资源目录 详见
| └─ios iOS原生资源目录 详见
├─hybrid App端存放本地html文件的目录,(不重要)
├─wxcomponents 存放微信小程序、QQ小程序组件的目录,(不用管)
├─mycomponents 存放支付宝小程序组件的目录,(不用管)
├─swancomponents 存放百度小程序组件的目录,(不用管)
├─ttcomponents 存放抖音小程序、飞书小程序组件的目录,(不用管)
├─kscomponents 存放快手小程序组件的目录,(不用管)
├─jdcomponents 存放京东小程序组件的目录,(不用管)
├─unpackage 非工程代码,一般存放运行或发行的编译结果
├─main.js Vue初始化入口文件
├─App.vue 应用配置,用来配置App全局样式以及监听 应用生命周期
├─pages.json 配置页面路由、导航条、选项卡等页面类信息,详见
├─manifest.json 配置应用名称、appid、logo、版本等打包信息,详见
├─AndroidManifest.xml Android原生应用清单文件 详见
├─Info.plist iOS原生应用配置文件 详见
└─uni.scss 内置的常用样式变量
Tips
- HbuilderX 1.9.0+ 支持在根目录创建
ext.json、sitemap.json等小程序需要的文件。
三、页面
页面简介
uni-app项目中,一个页面就是一个符合Vue SFC规范的 vue 文件。
-
在 uni-app js 引擎版中,后缀名是
.vue文件或.nvue文件。 这些页面均全平台支持,差异在于当 uni-app 发行到App平台时,.vue文件会使用webview进行渲染,.nvue会使用原生进行渲染,详见:nvue原生渲染。一个页面可以同时存在vue和nvue,在pages.json的路由注册中不包含页面文件名后缀,同一个页面可以对应2个文件名。重名时优先级如下:
- 在非app平台,先使用vue,忽略nvue
- 在app平台,使用nvue,忽略vue
页面管理
新建页面
uni-app中的页面,默认保存在工程根目录下的pages目录下。
每次新建页面,均需在
pages.json中配置pages列表;未在pages.json -> pages中注册的页面,uni-app会在编译阶段进行忽略。pages.json的完整配置参考:页面配置。通过HBuilderX开发
uni-app项目时,在uni-app项目上右键"新建页面",HBuilderX会自动在pages.json中完成页面注册,开发更方便。(推荐)

删除页面
删除页面时,需做两件工作:
- 删除
.vue文件、.nvue、.uvue文件 - 删除
pages.json -> pages列表项中的配置 (如使用HBuilderX删除页面,会在状态栏提醒删除pages.json对应内容,点击后会打开pages.json并定位到相关配置项)
页面改名
操作和删除页面同理,依次修改文件和
pages.json。
设置应用首页
pages.json -> pages配置项中的第一个页面,作为当前工程的首页(启动页)。
页面内容构成
uni-app 页面基于 vue 规范。一个页面内,有3个根节点标签:
- 模板组件区
<template> - 脚本区
<script> - 样式区
<style>
vue
<template>
<view class="content">
<image class="logo" src="/static/logo.png"></image>
<view class="text-area">
<text class="title">{{title}}</text>
</view>
</view>
</template>
<script setup>
import { ref } from 'vue'
import { onReady } from '@dcloudio/uni-app'
const title = ref('Hello uniapp')
onReady(() => {
console.log('onReady')
})
</script>
<style>
.content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.logo {
height: 200rpx;
width: 200rpx;
margin-top: 200rpx;
margin-left: auto;
margin-right: auto;
margin-bottom: 50rpx;
}
.text-area {
display: flex;
justify-content: center;
}
.title {
font-size: 36rpx;
color: #8f8f94;
}
</style>
页面调用接口
getApp()函数用于获取当前应用实例,一般用于获取globalData。也可通过应用实例调用App.vue methods中定义的方法。getCurrentPages()函数用于获取当前页面栈的实例,以数组形式按栈的顺序给出,数组中的元素为页面实例,第一个元素为首页,最后一个元素为当前页面。
四、互相引用
引入组件
传统vue项目开发,引用组件需要
导入 - 注册 - 使用三个步骤,如下:
html
<template>
<view>
<!-- 3.使用组件 -->
<uni-rate text="1"></uni-rate>
</view>
</template>
<script>
// 1. 导入组件
import uniRate from '@/components/uni-rate/uni-rate.vue';
export default {
components: { uniRate } // 2. 注册组件
}
</script>
Vue 3.x增加了
script setup特性,将三步优化为两步,无需注册步骤,更为简洁:
html
<template>
<view>
<!-- 2.使用组件 -->
<uni-rate text="1"></uni-rate>
</view>
</template>
<script setup>
// 1. 导入组件
import uniRate from '@/components/uni-rate/uni-rate.vue';
</script>
uni-app的easycom机制,将组件引用进一步优化,开发者只管使用,无需考虑导入和注册,更为高效:
html
<template>
<view>
<!-- 1.使用组件 -->
<uni-rate text="1"></uni-rate>
</view>
</template>
<script>
</script>
在 uni-app 项目中,页面引用组件和组件引用组件的方式都是一样的(可以理解为:页面是一种特殊的组件),均支持通过 easycom 方式直接引用。
引入js
js 文件引入
js文件或script标签内(包括 renderjs 等)引入js文件时,可以使用相对路径和绝对路径,形式如下
js
// 绝对路径,@指向项目根目录,在cli项目中@指向src目录
import add from '@/common/add.js';
// 相对路径
import add from '../../common/add.js';
注意
- js 文件不支持使用
/开头的方式引入
NPM支持
uni-app支持使用npm安装第三方包。
引入css
使用
@import语句可以导入外联样式表,@import后跟需要导入的外联样式表的相对路径,用;表示语句结束。
html
<style>
@import "../../common/uni.css";
.uni-card {
box-shadow: none;
}
</style>
引入静态资源
template内引入静态资源,如image、video等标签的src属性时,可以使用相对路径或者绝对路径,形式如下
html
<!-- 绝对路径,/static指根目录下的static目录,在cli项目中/static指src目录下的static目录 -->
<image class="logo" src="/static/logo.png"></image>
<image class="logo" src="@/static/logo.png"></image>
<!-- 相对路径 -->
<image class="logo" src="../../static/logo.png"></image>
五、js语法
uni-app的js API由标准ECMAScript的js API 和 uni 扩展 API 这两部分组成。
标准ECMAScript的js仅是最基础的js。浏览器基于它扩展了window、document、navigator等对象。小程序也基于标准js扩展了各种wx.xx、my.xx、swan.xx的API。node也扩展了fs等模块。
uni-app基于ECMAScript扩展了uni对象,并且API命名与小程序保持兼容。
六、css语法
uni-app 的 css 与 web 的 css 基本一致。
css预处理器支持
uni-app 支持less、sass、scss、stylus等预处理器。
vue2开发者sass预处理注意:
-
sass的预处理器,早年使用node-sass,也就是vue2最初默认的编译器。
-
sass官方推出了dart-sass来替代。node-sass已经停维很久了。
-
vue3默认使用的是
dart-sass。 -
另外node-sass不支持arm cpu,也即Apple的M系列CPU,导致HBuilderX的arm版只能使用dart-sass。
尺寸单位
uni-app支持的通用 css 单位包括 px、rpx
- px 即屏幕像素
- rpx 即响应式 px,一种根据屏幕宽度自适应的动态单位。以 750 宽的屏幕为基准,750rpx 恰好为屏幕宽度。屏幕变宽,rpx 实际显示效果会等比放大,但在 App(vue2 不含 nvue) 端和 H5(vue2) 端屏幕宽度达到 960px 时,默认将按照 375px 的屏幕宽度进行计算,具体配置参考:rpx 计算配置 。
选择器
目前支持的选择器有:
| 选择器 | 样例 | 样例描述 |
|---|---|---|
| .class | .intro | 选择所有拥有 class="intro" 的组件 |
| #id | #firstname | 选择拥有 id="firstname" 的组件 |
| element | view | 选择所有 view 组件 |
| element, element | view, checkbox | 选择所有文档的 view 组件和所有的 checkbox 组件 |
| ::after | view::after | 在 view 组件后边插入内容,仅 vue 页面生效 |
| ::before | view::before | 在 view 组件前边插入内容,仅 vue 页面生效 |
全局样式与局部样式
定义在
App.vue中的样式为全局样式,作用于每一个页面。在 pages 目录下 的vue 文件中定义的样式为局部样式,只作用在对应的页面,并会覆盖 App.vue 中相同的选择器。
注意:
- App.vue 中通过
@import语句可以导入外联样式,一样作用于每一个页面。 - nvue 页面暂不支持全局样式
固定值
uni-app 中以下组件的高度是固定的,不可修改:
| 组件 | 描述 | App | H5 |
|---|---|---|---|
| NavigationBar | 导航栏 | 44px | 44px |
| TabBar | 底部选项卡 | HBuilderX 2.3.4 之前为 56px,2.3.4 起和 H5 调为一致,统一为 50px。(但可以自主更改高度) | 50px |
Flex 布局
为支持跨平台,框架建议使用 Flex 布局,关于 Flex 布局可以参考外部文档A Complete Guide to Flexbox、阮一峰的 flex 教程等。
背景图片
uni-app 支持使用在 css 里设置背景图片,使用方式与普通 web 项目大体相同,但需要注意以下几点:
-
支持 base64 格式图片。
-
支持网络路径图片。
-
小程序不支持在 css 中使用本地文件,包括本地的背景图和字体文件。需以 base64 方式方可使用。
-
使用本地路径背景图片需注意:
-
为方便开发者,在背景图片小于 40kb 时,
uni-app编译到不支持本地背景图的平台时,会自动将其转化为 base64 格式; -
图片大于等于 40kb,会有性能问题,不建议使用太大的背景图,如开发者必须使用,则需自己将其转换为 base64 格式使用,或将其挪到服务器上,从网络地址引用。
-
本地背景图片的引用路径推荐使用以 ~@ 开头的绝对路径。
css.test2 { background-image: url('~@/static/logo.png'); }
-
注意
- 微信小程序不支持相对路径(真机不支持,开发工具支持)
七、vue语法
https://uniapp.dcloud.net.cn/tutorial/vue3-basics.html
八、条件编译
什么是编译器
uni-app能实现一套代码、多端运行,核心是通过编译器 + 运行时实现的:
- 编译器:将
uni-app统一代码编译生成每个平台支持的特有代码;如在小程序平台,编译器将.vue文件拆分生成wxml、wxss、js等代码。 - 运行时:动态处理数据绑定、事件代理,保证Vue和平台宿主数据的一致性;
uni-app项目根据所依赖的Vue版本不同,编译器的实现也不同:
- vue2:
uni-app编译器基于wepback实现 - vue3:
uni-app编译器基于Vite实现,编译速度更快
条件编译处理多端差异
为什么选择条件编译处理跨端兼容
uni-app 已将常用的组件、API 封装到框架中,开发者按照 uni-app 规范开发即可保证多平台兼容,大部分业务均可直接满足。
但每个平台有自己的一些特性,因此会存在一些无法跨平台的情况。
- 大量写 if else,会造成代码执行性能低下和管理混乱。
- 编译到不同的工程后二次修改,会让后续升级变的很麻烦。
- 为每个平台重写,明明主业务逻辑又一样
在 C 语言中,通过 #ifdef、#ifndef 的方式,为 Windows、Mac 等不同 OS 编译不同的代码。
uni-app 团队参考这个思路,为 uni-app 提供了条件编译手段,在一个工程里优雅的完成了平台个性化实现。
条件编译
条件编译是用特殊的注释作为标记,在编译时根据这些特殊的注释,将注释里面的代码编译到不同平台。
使用方法
以 #ifdef 或 #ifndef 加 %PLATFORM% 开头,以 #endif 结尾。
#ifdef:if defined 仅在某平台存在#ifndef:if not defined 除了某平台均存在%PLATFORM%:平台名称
| 条件编译写法 | 说明 |
|---|---|
| #ifdef APP-PLUS 需条件编译的代码 #endif | 仅出现在 App 平台下的代码 |
| #ifndef H5 需条件编译的代码 #endif | 除了 H5 平台,其它平台均存在的代码(注意if后面有个n) |
| #ifdef H5 || MP-WEIXIN 需条件编译的代码 #endif | 在 H5 平台或微信小程序平台存在的代码 |
| #ifdef APP && VUE3-VAPOR 需条件编译的代码 #endif | 在 APP 平台且蒸汽模式下存在的代码 |
| #ifdef APP && !VUE3-VAPOR 需条件编译的代码 #endif | 在 APP 平台且非蒸汽模式下存在的代码(注意VUE3-VAPOR前面有个!) |
API 的条件编译
css
// #ifdef %PLATFORM%
平台特有的API实现
// #endif
组件的条件编译
css
<!-- #ifdef %PLATFORM% -->
平台特有的组件
<!-- #endif -->
样式的条件编译
css
/* #ifdef %PLATFORM% */
平台特有样式
/* #endif */
注意: 样式的条件编译,无论是 css 还是 sass/scss/less/stylus 等预编译语言中,必须使用 /*注释*/ 的写法。
pages.json 的条件编译
下面的页面,只有运行至 App 时才会编译进去。

整体目录条件编译
如果想把各平台的页面文件更彻底的分开,也可以在 uni-app 项目根目录创建platforms目录,然后在下面进一步创建app-plus、mp-weixin等子目录,存放不同平台的文件。
注意
platforms目录下只支持放置页面文件(即页面 vue 文件),如果需要对其他资源条件编译,建议使用static 目录的条件编译。