```uni-app``` 使用vue的语法+小程序的标签和API。 ## 开发规范 为了实现多端兼容,综合考虑编译速度、运行性能等因素,```uni-app``` 约定了如下开发规范: - 页面文件遵循 [Vue 单文件组件 (SFC) 规范](https://vue-loader.vuejs.org/zh/spec.html) - 组件标签靠近小程序规范,详见[uni-app 组件规范](component/README.md) - 接口能力(JS API)靠近微信小程序规范,但需将前缀 ```wx``` 替换为 ```uni```,详见[uni-app接口规范](api/README.md) - 数据绑定及事件处理同 ```Vue.js``` 规范,同时补充了App及页面的生命周期 - 为兼容多端运行,建议使用flex布局进行开发 ## 目录结构 一个uni-app工程,默认包含如下目录及文件:
	
┌─uniCloud              云空间目录,阿里云为uniCloud-aliyun,腾讯云为uniCloud-tcb(详见uniCloud)
│─components            符合vue组件规范的uni-app组件目录
│  └─comp-a.vue         可复用的a组件
├─hybrid                App端存放本地html文件的目录,详见
├─platforms             存放各平台专用页面的目录,详见
├─pages                 业务页面文件存放的目录
│  ├─index
│  │  └─index.vue       index页面
│  └─list
│     └─list.vue        list页面
├─static                存放应用引用的本地静态资源(如图片、视频等)的目录,注意:静态资源只能存放于此
├─uni_modules           存放[uni_module](/uni_modules)规范的插件。
├─wxcomponents          存放小程序组件的目录,详见
├─main.js               Vue初始化入口文件
├─App.vue               应用配置,用来配置App全局样式以及监听 应用生命周期
├─manifest.json         配置应用名称、appid、logo、版本等打包信息,详见
├─pages.json            配置页面路由、导航条、选项卡等页面类信息,详见
└─uni.scss              这里是uni-app内置的常用样式变量 
	
**Tips** - 编译到任意平台时,`static` 目录下的文件均会被完整打包进去,且不会编译。非 `static` 目录下的文件(vue、js、css 等)只有被引用到才会被打包编译进去。 - `static` 目录下的 `js` 文件不会被编译,如果里面有 `es6` 的代码,不经过转换直接运行,在手机设备上会报错。 - `css`、`less/scss` 等资源不要放在 `static` 目录下,建议这些公用的资源放在自建的 `common` 目录下。 - HbuilderX 1.9.0+ 支持在根目录创建 `ext.json`、`sitemap.json` 等小程序需要的文件。 |有效目录|说明| |:-:|:-:| |app-plus|App| |h5|H5| |mp-weixin|微信小程序| |mp-alipay|支付宝小程序| |mp-baidu|百度小程序| |mp-qq|QQ小程序| |mp-toutiao|字节小程序| |mp-lark|飞书小程序| |mp-kuaishou|快手小程序| ## 资源路径说明 ### 模板内引入静态资源 > `template`内引入静态资源,如`image`、`video`等标签的`src`属性时,可以使用相对路径或者绝对路径,形式如下 ```html ``` **注意** - `@`开头的绝对路径以及相对路径会经过base64转换规则校验 - 引入的静态资源在非h5平台,均不转为base64。 - H5平台,小于4kb的资源会被转换成base64,其余不转。 - 自`HBuilderX 2.6.6`起`template`内支持`@`开头路径引入静态资源,旧版本不支持此方式 - App平台自`HBuilderX 2.6.9`起`template`节点中引用静态资源文件时(如:图片),调整查找策略为【基于当前文件的路径搜索】,与其他平台保持一致 - 支付宝小程序组件内 image 标签不可使用相对路径 ### js文件引入 > `js`文件或`script`标签内(包括renderjs等)引入`js`文件时,可以使用相对路径和绝对路径,形式如下 ```js // 绝对路径,@指向项目根目录,在cli项目中@指向src目录 import add from '@/common/add.js' // 相对路径 import add from '../../common/add.js' ``` **注意** - js文件不支持使用`/`开头的方式引入 ### css引入静态资源 > `css`文件或`style标签`内引入`css`文件时(scss、less文件同理),可以使用相对路径或绝对路径(`HBuilderX 2.6.6`) ```css /* 绝对路径 */ @import url('/common/uni.css'); @import url('@/common/uni.css'); /* 相对路径 */ @import url('../../common/uni.css'); ``` **注意** - 自`HBuilderX 2.6.6`起支持绝对路径引入静态资源,旧版本不支持此方式 > `css`文件或`style标签`内引用的图片路径可以使用相对路径也可以使用绝对路径,需要注意的是,有些小程序端css文件不允许引用本地文件(请看注意事项)。 ```css /* 绝对路径 */ background-image: url(/static/logo.png); background-image: url(@/static/logo.png); /* 相对路径 */ background-image: url(../../static/logo.png); ``` **Tips** - 引入字体图标请参考,[字体图标](frame?id=字体图标) - `@`开头的绝对路径以及相对路径会经过base64转换规则校验 - 不支持本地图片的平台,小于40kb,一定会转base64。(共四个平台mp-weixin, mp-qq, mp-toutiao, app v2) - h5平台,小于4kb会转base64,超出4kb时不转。 - 其余平台不会转base64 ## 生命周期 ### 应用生命周期 ``uni-app`` 支持 onLaunch、onShow、onHide 等应用生命周期函数,详情请参考[应用生命周期](/collocation/frame/lifecycle?id=应用生命周期) ### 页面生命周期 ``uni-app`` 支持 onLoad、onShow、onReady 等生命周期函数,详情请参考[页面生命周期](/collocation/frame/lifecycle?id=页面生命周期) ## 路由 ``uni-app``页面路由为框架统一管理,开发者需要在[pages.json](/collocation/pages?id=pages)里配置每个路由页面的路径及页面样式。类似小程序在app.json中配置页面路由一样。所以 `uni-app` 的路由用法与 ``Vue Router`` 不同,如仍希望采用 `Vue Router` 方式管理路由,可在插件市场搜索 [Vue-Router](https://ext.dcloud.net.cn/search?q=vue-router)。 ### 路由跳转 ``uni-app`` 有两种页面路由跳转方式:使用[navigator](/component/navigator)组件跳转、调用[API](/api/router)跳转。 ### 页面栈 框架以栈的形式管理当前所有页面, 当发生路由切换的时候,页面栈的表现如下: |路由方式 |页面栈表现 |触发时机 | |--- |--- |--- | |初始化 |新页面入栈 |uni-app 打开的第一个页面 | |打开新页面 |新页面入栈 |调用 API   [uni.navigateTo](/api/router?id=navigateto)  、使用组件  <navigator open-type="navigate"/> | |页面重定向 |当前页面出栈,新页面入栈 |调用 API   [uni.redirectTo](/api/router?id=redirectto)  、使用组件  <navigator open-type="redirectTo"/> | |页面返回 |页面不断出栈,直到目标返回页 |调用 API  [uni.navigateBack](/api/router?id=navigateback)   、使用组件 <navigator open-type="navigateBack"/> 、用户按左上角返回按钮、安卓用户点击物理back按键 | |Tab 切换 |页面全部出栈,只留下新的 Tab 页面 |调用 API  [uni.switchTab](/api/router?id=switchtab)  、使用组件  <navigator open-type="switchTab"/>  、用户切换 Tab | |重加载 |页面全部出栈,只留下新的页面 |调用 API  [uni.reLaunch](/api/router?id=relaunch)  、使用组件  <navigator open-type="reLaunch"/> | ## 运行环境判断 ### 开发环境和生产环境 ``uni-app`` 可通过 ``process.env.NODE_ENV`` 判断当前环境是开发环境还是生产环境。一般用于连接测试服务器或生产服务器的动态切换。 - 在HBuilderX 中,点击“运行”编译出来的代码是开发环境,点击“发行”编译出来的代码是生产环境 - cli模式下,是通行的编译环境处理方式。 ```javascript if(process.env.NODE_ENV === 'development'){ console.log('开发环境') }else{ console.log('生产环境') } ``` 如果你需要自定义更多环境,比如测试环境: - 假设只需要对单一平台配置,可以 package.json 中配置,在HBuilderX的运行和发行菜单里会多一个出来。[https://uniapp.dcloud.io/collocation/package](https://uniapp.dcloud.io/collocation/package) - 如果是针对所有平台配置,可以在 vue-config.js 中配置。[https://uniapp.dcloud.io/collocation/vue-config](https://uniapp.dcloud.io/collocation/vue-config) **快捷代码块** HBuilderX 中敲入代码块 `uEnvDev`、`uEnvProd` 可以快速生成对应 `development`、`production` 的运行环境判定代码。 ```javascript // uEnvDev if (process.env.NODE_ENV === 'development') { // TODO } // uEnvProd if (process.env.NODE_ENV === 'production') { // TODO } ``` ### 判断平台 平台判断有2种场景,一种是在编译期判断,一种是在运行期判断。 - 编译期判断 编译期判断,即条件编译,不同平台在编译出包后已经是不同的代码。详见:[条件编译](/platform) ```javascript // #ifdef H5 alert("只有h5平台才有alert方法") // #endif ``` 如上代码只会编译到H5的发行包里,其他平台的包不会包含如上代码。 - 运行期判断 运行期判断是指代码已经打入包中,仍然需要在运行期判断平台,此时可使用 ``uni.getSystemInfoSync().platform`` 判断客户端环境是 Android、iOS 还是小程序开发工具(在百度小程序开发工具、微信小程序开发工具、支付宝小程序开发工具中使用 ``uni.getSystemInfoSync().platform`` 返回值均为 devtools)。 ```javascript switch(uni.getSystemInfoSync().platform){ case 'android': console.log('运行Android上') break; case 'ios': console.log('运行iOS上') break; default: console.log('运行在开发者工具上') break; } ``` 如有必要,也可以在条件编译里自己定义一个变量,赋不同值。在后续运行代码中动态判断环境。 ### 其他环境变量 其他环境变量的定义方式参考 [环境变量](/collocation/env)。 ## 页面样式与布局 uni-app的css与web的css基本一致。本文没有讲解css的用法。在你了解web的css的基础之上,本文讲述一些样式相关的注意事项。 uni-app有vue页面和nvue页面。vue页面是webview渲染的、app端的nvue页面是原生渲染的。在nvue页面里样式比web会限制更多,另见[nvue样式专项文档](/nvue-css) 本文重点介绍vue页面的样式注意事项。 ### 尺寸单位 `uni-app` 支持的通用 css 单位包括 px、rpx - px 即屏幕像素 - rpx 即响应式px,一种根据屏幕宽度自适应的动态单位。以750宽的屏幕为基准,750rpx恰好为屏幕宽度。屏幕变宽,rpx 实际显示效果会等比放大,但在 App(vue2 不含 nvue) 端和 H5(vue2) 端屏幕宽度达到 960px 时,默认将按照 375px 的屏幕宽度进行计算,具体配置参考:[rpx计算配置](/collocation/pages?id=globalstyle) 。 vue页面支持下面这些普通H5单位,但在nvue里不支持: - rem 根字体大小可以通过 [page-meta](/component/page-meta?id=page-meta) 配置字节跳动小程序和飞书小程序:屏幕宽度/20、百度小程序:16px、支付宝小程序:50px - vh viewpoint height,视窗高度,1vh等于视窗高度的1% - vw viewpoint width,视窗宽度,1vw等于视窗宽度的1% nvue还不支持百分比单位。 App端,在 pages.json 里的 titleNView 或页面里写的 plus api 中涉及的单位,只支持 px。**注意此时不支持 rpx** nvue中,uni-app 模式([nvue 不同编译模式介绍](https://ask.dcloud.net.cn/article/36074))可以使用 px 、rpx,表现与 vue 中基本一致,另外启用 [dynamicRpx](/collocation/pages?id=globalstyle) 后可以适配屏幕大小动态变化。weex 模式目前遵循weex的单位,它的单位比较特殊: - px:,以750宽的屏幕为基准动态计算的长度单位,与 vue 页面中的 rpx 理念相同。(一定要注意 weex 模式的 px,和 vue 里的 px 逻辑不一样。) - wx:与设备屏幕宽度无关的长度单位,与 vue 页面中的 px 理念相同 下面对 `rpx` 详细说明: 设计师在提供设计图时,一般只提供一个分辨率的图。 严格按设计图标注的 px 做开发,在不同宽度的手机上界面很容易变形。 而且主要是宽度变形。高度一般因为有滚动条,不容易出问题。由此,引发了较强的动态宽度单位需求。 微信小程序设计了 rpx 解决这个问题。`uni-app` 在 App 端、H5 端都支持了 `rpx`,并且可以配置不同屏幕宽度的计算方式,具体参考:[rpx计算配置](https://uniapp.dcloud.io/collocation/pages?id=globalstyle)。 rpx 是相对于基准宽度的单位,可以根据屏幕宽度进行自适应。```uni-app``` 规定屏幕基准宽度 750rpx。 开发者可以通过设计稿基准宽度计算页面元素 rpx 值,设计稿 1px 与框架样式 1rpx 转换公式如下: ```设计稿 1px / 设计稿基准宽度 = 框架样式 1rpx / 750rpx``` 换言之,页面元素宽度在 `uni-app` 中的宽度计算公式: ``` 750 * 元素在设计稿中的宽度 / 设计稿基准宽度 ``` **举例说明:** 1. 若设计稿宽度为 750px,元素 A 在设计稿上的宽度为 100px,那么元素 A 在 `uni-app` 里面的宽度应该设为:`750 * 100 / 750`,结果为:100rpx。 2. 若设计稿宽度为 640px,元素 A 在设计稿上的宽度为 100px,那么元素 A 在 `uni-app` 里面的宽度应该设为:`750 * 100 / 640`,结果为:117rpx。 2. 若设计稿宽度为 375px,元素 B 在设计稿上的宽度为 200px,那么元素 B 在 `uni-app` 里面的宽度应该设为:` 750 * 200 / 375`,结果为:400rpx。 **Tips** - 注意 rpx 是和宽度相关的单位,屏幕越宽,该值实际像素越大。如不想根据屏幕宽度缩放,则应该使用 px 单位。 - 如果开发者在字体或高度中也使用了 rpx ,那么需注意这样的写法意味着随着屏幕变宽,字体会变大、高度会变大。如果你需要固定高度,则应该使用 px 。 - rpx不支持动态横竖屏切换计算,使用rpx建议锁定屏幕方向 - 设计师可以用 iPhone6 作为视觉稿的标准。 - 如果设计稿不是750px,HBuilderX提供了自动换算的工具,详见:[https://ask.dcloud.net.cn/article/35445](https://ask.dcloud.net.cn/article/35445)。 - App端,在 pages.json 里的 titleNView 或页面里写的 plus api 中涉及的单位,只支持 px,不支持 rpx。 - 早期 uni-app 提供了 upx ,目前已经推荐统一改为 rpx 了,[详见](http://ask.dcloud.net.cn/article/36130) ### 样式导入 使用```@import```语句可以导入外联样式表,```@import```后跟需要导入的外联样式表的相对路径,用```;```表示语句结束。 **示例代码:** ``` ``` ### 内联样式 框架组件上支持使用 style、class 属性来控制组件的样式。 - style:静态的样式统一写到 class 中。style 接收动态的样式,在运行时会进行解析,请尽量避免将静态的样式写进 style 中,以免影响渲染速度。 ``` ``` - class:用于指定样式规则,其属性值是样式规则中类选择器名(样式类名)的集合,样式类名不需要带上.,样式类名之间用空格分隔。 ``` ``` ### 选择器 目前支持的选择器有: |选择器|样例|样例描述| |:-|:-|:-| |.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 页面生效**| **注意:** - 在 ```uni-app``` 中不能使用 ```*``` 选择器。 - 微信小程序自定义组件中仅支持 class 选择器 - ```page``` 相当于 ```body``` 节点,例如: ```css page { background-color:#ccc; } ``` ### 全局样式与局部样式 定义在 App.vue 中的样式为全局样式,作用于每一个页面。在 pages 目录下 的 vue 文件中定义的样式为局部样式,只作用在对应的页面,并会覆盖 App.vue 中相同的选择器。 **注意:** - App.vue 中通过 ``@import`` 语句可以导入外联样式,一样作用于每一个页面。 - nvue页面暂不支持全局样式 ### CSS变量 uni-app 提供内置 CSS 变量 |CSS变量|描述|App|小程序|H5| |:-|:-|:-|:-|:-| |--status-bar-height|系统状态栏高度|[系统状态栏高度](http://www.html5plus.org/doc/zh_cn/navigator.html#plus.navigator.getStatusbarHeight)、nvue注意见下|25px|0| |--window-top|内容区域距离顶部的距离|0|0|NavigationBar 的高度| |--window-bottom|内容区域距离底部的距离|0|0|TabBar 的高度| **注意:** - ``var(--status-bar-height)`` 此变量在微信小程序环境为固定 ``25px``,在 App 里为手机实际状态栏高度。 - 当设置 ``"navigationStyle":"custom"`` 取消原生导航栏后,由于窗体为沉浸式,占据了状态栏位置。此时可以使用一个高度为 ``var(--status-bar-height)`` 的 view 放在页面顶部,避免页面内容出现在状态栏。 - 由于在H5端,不存在原生导航栏和tabbar,也是前端div模拟。如果设置了一个固定位置的居底view,在小程序和App端是在tabbar上方,但在H5端会与tabbar重叠。此时可使用`--window-bottom`,不管在哪个端,都是固定在tabbar上方。 - 目前 nvue 在App端,还不支持 `--status-bar-height`变量,替代方案是在页面onLoad时通过uni.getSystemInfoSync().statusBarHeight获取状态栏高度,然后通过style绑定方式给占位view设定高度。下方提供了示例代码 **代码块** 快速书写css变量的方法是:在css中敲hei,在候选助手中即可看到3个css变量。(HBuilderX 1.9.6以上支持) 示例1 - 普通页面使用css变量: ```html ``` ```html ``` 示例2 - nvue页面获取状态栏高度 ```html ``` ### 固定值 `uni-app` 中以下组件的高度是固定的,不可修改: |组件|描述|App|H5| |:-|:-|:-|:-| |NavigationBar|导航栏|44px|44px| |TabBar|底部选项卡|HBuilderX 2.3.4之前为56px,2.3.4起和H5调为一致,统一为 50px。但可以自主更改高度)|50px| 各小程序平台,包括同小程序平台的iOS和Android的高度也不一样。 ### Flex布局 为支持跨平台,框架建议使用Flex布局,关于Flex布局可以参考外部文档[A Complete Guide to Flexbox](https://css-tricks.com/snippets/css/a-guide-to-flexbox/)、[阮一峰的flex教程](http://www.ruanyifeng.com/blog/2015/07/flex-grammar.html)等。 ### 背景图片 ``uni-app`` 支持使用在 css 里设置背景图片,使用方式与普通 ``web`` 项目大体相同,但需要注意以下几点: - 支持 base64 格式图片。 - 支持网络路径图片。 - 小程序不支持在css中使用本地文件,包括本地的背景图和字体文件。需以base64方式方可使用。 - 使用本地路径背景图片需注意: 1. 为方便开发者,在背景图片小于 40kb 时,``uni-app`` 编译到不支持本地背景图的平台时,会自动将其转化为 base64 格式; 2. 图片大于等于 40kb,会有性能问题,不建议使用太大的背景图,如开发者必须使用,则需自己将其转换为 base64 格式使用,或将其挪到服务器上,从网络地址引用。 3. 本地背景图片的引用路径推荐使用以 ~@ 开头的绝对路径。 ```css .test2 { background-image: url('~@/static/logo.png'); } ``` **注意** - 微信小程序不支持相对路径(真机不支持,开发工具支持) ### 字体图标 ``uni-app`` 支持使用字体图标,使用方式与普通 ``web`` 项目相同,需要注意以下几点: - 支持 base64 格式字体图标。 - 支持网络路径字体图标。 - 小程序不支持在css中使用本地文件,包括本地的背景图和字体文件。需以base64方式方可使用。 - 网络路径必须加协议头 ``https``。 - 从 [http://www.iconfont.cn](http://www.iconfont.cn) 上拷贝的代码,默认是没加协议头的。 - 从 [http://www.iconfont.cn](http://www.iconfont.cn) 上下载的字体文件,都是同名字体(字体名都叫iconfont,安装字体文件时可以看到),在nvue内使用时需要注意,此字体名重复可能会显示不正常,可以使用工具修改。 - 使用本地路径图标字体需注意: 1. 为方便开发者,在字体文件小于 40kb 时,``uni-app`` 会自动将其转化为 base64 格式; 2. 字体文件大于等于 40kb,仍转换为 base64 方式使用的话可能有性能问题,如开发者必须使用,则需自己将其转换为 base64 格式使用,或将其挪到服务器上,从网络地址引用; 3. 字体文件的引用路径推荐使用以 ~@ 开头的绝对路径。 ```css @font-face { font-family: test1-icon; src: url('~@/static/iconfont.ttf'); } ``` `nvue`中不可直接使用css的方式引入字体文件,需要使用以下方式在js内引入。nvue内不支持本地路径引入字体,请使用网络链接或者`base64`形式。**`src`字段的`url`的括号内一定要使用单引号。** ```js var domModule = weex.requireModule('dom'); domModule.addRule('fontFace', { 'fontFamily': "fontFamilyName", 'src': "url('https://...')" }) ``` **示例:** ```html ``` ## ``