uni-app(4):js语法、css语法
1 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命名与小程序保持兼容。
1.1 标准js和浏览器js的区别
uni-app
的js代码,h5端运行于浏览器中。非h5端(包含小程序和App),Android平台运行在v8引擎中,iOS平台运行在iOS自带的jscore引擎中,都没有运行在浏览器或webview里。非H5端,虽然不支持window、document、navigator等浏览器的js API,但也支持标准ECMAScript。请注意不要把浏览器里的js扩展对象等价于标准js。
所以uni-app的非H5端,一样支持标准js,支持if、for等语法,支持字符串、数字、时间、布尔值、数组、自定义对象等变量类型及各种处理方法。仅仅是不支持window、document、navigator等浏览器专用对象。
1.2 ES6 支持
uni-app 在支持绝大部分 ES6 API 的同时,也支持了 ES7 的 await/async。ES6 API 的支持,详见如下表格部分(x
表示不支持,无特殊说明则表示支持):
String | iOS8 | iOS9 | iOS10 | Android |
---|---|---|---|---|
codePointAt | ||||
normalize | x | x | 仅支持 NFD/NFC | |
includes | ||||
startsWith | ||||
endsWith | ||||
repeat | ||||
String.fromCodePoint |
Array | iOS8 | iOS9 | iOS10 | Android |
---|---|---|---|---|
copyWithin | ||||
find | ||||
findIndex | ||||
fill | ||||
entries | ||||
keys | ||||
values | x | x | ||
includes | x | |||
Array.from | ||||
Array.of |
Number | iOS8 | iOS9 | iOS10 | Android |
---|---|---|---|---|
isFinite | ||||
isNaN | ||||
parseInt | ||||
parseFloat | ||||
isInteger | ||||
EPSILON | ||||
isSafeInteger |
Math | iOS8 | iOS9 | iOS10 | Android |
---|---|---|---|---|
trunc | ||||
sign | ||||
cbrt | ||||
clz32 | ||||
imul | ||||
fround | ||||
hypot | ||||
expm1 | ||||
log1p | ||||
log10 | ||||
log2 | ||||
sinh | ||||
cosh | ||||
tanh | ||||
asinh | ||||
acosh | ||||
atanh |
Object | iOS8 | iOS9 | iOS10 | Android |
---|---|---|---|---|
is | ||||
assign | ||||
getOwnPropertyDescriptor | ||||
keys | ||||
getOwnPropertyNames | ||||
getOwnPropertySymbols |
Other | iOS8 | iOS9 | iOS10 | Android<5 |
---|---|---|---|---|
Symbol | ||||
Set | ||||
Map | ||||
Proxy | x | x | x | |
Reflect | ||||
Promise |
默认不需要在微信工具里继续开启es6转换。但如果用了微信的wxml自定义组件(wxcomponents目录下),uni-app编译器并不会处理这些文件中的es6代码,需要去微信工具里开启转换。从HBuilderX调起微信工具时,如果发现工程下有wxcomponents目录会自动配置微信工程打开es6转换。
1.3 App端
在App端JS脚本运行在独立的JS引擎中,vue页面使用系统webview渲染,nvue页面使用系统原生View渲染。
Android平台
- JS脚本运行在独立Google V8引擎中,版本与Chrome83一致,因此支持的语法与Android系统版本无关,即便是Android4.4也与Chrome83支持的语法一样。
- vue页面渲染在系统Webview中,受Android系统版本影响,在Android低端机上存在css浏览器兼容性问题,太新的css语法在低版本不支持。当然也可以使用x5等三方webview来拉齐实现。
iOS平台
- JS脚本运行在iOS操作系统提供的JavaScriptCore 引擎,因此支持的语法与iOS系统有关,跟iOS系统的Safari浏览器一致。
- vue页面渲染在系统WKWebview中,受iOS系统版本影响,兼容性与iOS系统的Safari浏览器一致。
2 css语法
uni-app 有 vue 页面、nvue 页面、uvue页面。 uni-app 的 css 与 web 的 css 基本一致。
- vue 页面是 webview 渲染的
- app-nvue 页面是原生渲染的,其样式比 web 会限制更多
- app-uvue 页面是原生渲染的,是 web 的css子集
2.1 css预处理器支持
uni-app 支持less、sass、scss、stylus等预处理器。sass的预处理器,早年使用node-sass,也就是vue2最初默认的编译器。sass官方推出了dart-sass来替代。node-sass已经停维很久了。vue3默认使用的是dart-sass。DCloud推荐开发者尽快升级到vue3,改用dart-sass。
2.2 尺寸单位
uni-app
支持的通用 css 单位包括 px、rpx
- px 即屏幕像素
- rpx 即响应式 px,一种根据屏幕宽度自适应的动态单位。以 750 宽的屏幕为基准,750rpx 恰好为屏幕宽度。屏幕变宽,rpx 实际显示效果会等比放大,但在 App(vue2 不含 nvue) 端和 H5(vue2) 端屏幕宽度达到 960px 时,默认将按照 375px 的屏幕宽度进行计算
vue 页面支持下面这些普通 H5 单位,但在 nvue 里不支持:
- rem 根字体大小可以通过 page-meta 配置抖音小程序和飞书小程序:屏幕宽度/20、百度小程序:16px、支付宝小程序:50px
- vh viewpoint height,视窗高度,1vh 等于视窗高度的 1%
- vw viewpoint width,视窗宽度,1vw 等于视窗宽度的 1%
nvue 还不支持百分比单位。App 端,在 pages.json 里的 titleNView 或页面里写的 plus api 中涉及的单位,只支持 px。nvue 中,uni-app 模式可以使用 px 、rpx,表现与 vue 中基本一致,另外启用 dynamicRpx 后可以适配屏幕大小动态变化。weex 模式目前遵循 weex 的单位,它的单位比较特殊:
- px:,以 750 宽的屏幕为基准动态计算的长度单位,与 vue 页面中的 rpx 理念相同。(一定要注意 weex 模式的 px,和 vue 里的 px 逻辑不一样。)
- wx:与设备屏幕宽度无关的长度单位,与 vue 页面中的 px 理念相同
rpx
详细说明:设计师在提供设计图时,一般只提供一个分辨率的图。严格按设计图标注的 px 做开发,在不同宽度的手机上界面很容易变形。而且主要是宽度变形。高度一般因为有滚动条,不容易出问题。由此,引发了较强的动态宽度单位需求。
微信小程序设计了 rpx 解决这个问题。uni-app
在 App 端、H5 端都支持了 rpx
,并且可以配置不同屏幕宽度的计算方式rpx 是相对于基准宽度的单位,可以根据屏幕宽度进行自适应。uni-app
规定屏幕基准宽度 750rpx。开发者可以通过设计稿基准宽度计算页面元素 rpx 值,设计稿 1px 与框架样式 1rpx 转换公式如下:
设计稿 1px / 设计稿基准宽度 = 框架样式 1rpx / 750rpx
换言之,页面元素宽度在 uni-app
中的宽度计算公式:
750 * 元素在设计稿中的宽度 / 设计稿基准宽度
举例说明:
- 若设计稿宽度为 750px,元素 A 在设计稿上的宽度为 100px,那么元素 A 在
uni-app
里面的宽度应该设为:750 * 100 / 750
,结果为:100rpx。 - 若设计稿宽度为 640px,元素 A 在设计稿上的宽度为 100px,那么元素 A 在
uni-app
里面的宽度应该设为:750 * 100 / 640
,结果为:117rpx。 - 若设计稿宽度为 375px,元素 B 在设计稿上的宽度为 200px,那么元素 B 在
uni-app
里面的宽度应该设为:750 * 200 / 375
,结果为:400rpx。
- 注意 rpx 是和宽度相关的单位,屏幕越宽,该值实际像素越大。如不想根据屏幕宽度缩放,则应该使用 px 单位。
- 如果开发者在字体或高度中也使用了 rpx ,那么需注意这样的写法意味着随着屏幕变宽,字体会变大、高度会变大。如果你需要固定高度,则应该使用 px 。
- rpx 不支持动态横竖屏切换计算,使用 rpx 建议锁定屏幕方向
- 设计师可以用 iPhone6 作为视觉稿的标准。
- App 端,在 pages.json 里的 titleNView 或页面里写的 plus api 中涉及的单位,只支持 px,不支持 rpx。
- 早期 uni-app 提供了 upx ,目前已经推荐统一改为 rpx 了
2.3 样式导入
使用@import
语句可以导入外联样式表,@import
后跟需要导入的外联样式表的相对路径,用;
表示语句结束。
<style>@import "../../common/uni.css";.uni-card {box-shadow: none;}
</style>
2.4 内联样式
框架组件上支持使用 style、class 属性来控制组件的样式。
- style:静态的样式统一写到 class 中。style 接收动态的样式,在运行时会进行解析,请尽量避免将静态的样式写进 style 中,以免影响渲染速度。
<view :style="{color:color}" />
- class:用于指定样式规则,其属性值是样式规则中类选择器名(样式类名)的集合,样式类名不需要带上.,样式类名之间用空格分隔。
<view class="normal_view" />
2.5 选择器
选择器 | 样例 | 样例描述 |
---|---|---|
.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
节点,例如:
<!-- 设置页面背景颜色,使用 scoped 会导致失效 -- >
page {background-color: #ccc;
}
-
web端可以使用
html
、body
、:root
等选择器。由于页面的css样式隔离,且html节点并未添加data-xxx属性,html
、:root
写在页面style内无效,只能写在App.vue内。
2.6 全局样式与局部样式
定义在 App.vue 中的样式为全局样式,作用于每一个页面。在 pages 目录下 的 vue 文件中定义的样式为局部样式,只作用在对应的页面,并会覆盖 App.vue 中相同的选择器。
- App.vue 中通过
@import
语句可以导入外联样式,一样作用于每一个页面。 - nvue 页面暂不支持全局样式
2.7 CSS 变量
uni-app 提供内置 CSS 变量
CSS 变量 | 描述 | App | 小程序 | H5 |
---|---|---|---|---|
--status-bar-height | 系统状态栏高度 | 系统状态栏高度、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 变量。
示例 1 - 普通页面使用 css 变量:
<template><!-- HBuilderX 2.6.3+ 新增 page-meta --><page-meta><navigation-bar /></page-meta><view><view class="status_bar"><!-- 这里是状态栏 --></view><view>状态栏下的文字</view></view>
</template>
<style>.status_bar {height: var(--status-bar-height);width: 100%;}
</style>
<template><view><view class="toTop"><!-- 这里可以放一个向上箭头,它距离底部tabbar上浮10px--></view></view>
</template>
<style>.toTop {bottom: calc(var(--window-bottom) + 10px);}
</style>
示例 2 - nvue 页面获取状态栏高度
<template><view class="content"><view :style="{ height: iStatusBarHeight + 'px'}"></view></view>
</template><script>export default {data() {return {iStatusBarHeight: 0,};},onLoad() {this.iStatusBarHeight = uni.getSystemInfoSync().statusBarHeight;},};
</script>
2.8 固定值
uni-app
中以下组件的高度是固定的,不可修改:
组件 | 描述 | App | H5 |
---|---|---|---|
NavigationBar | 导航栏 | 44px | 44px |
TabBar | 底部选项卡 | HBuilderX 2.3.4 之前为 56px,2.3.4 起和 H5 调为一致,统一为 50px。(但可以自主更改高度) | 50px |
各小程序平台,包括同小程序平台的 iOS 和 Android 的高度也不一样。
2.9 Flex 布局
为支持跨平台,框架建议使用 Flex 布局。
2.10 背景图片
uni-app
支持使用在 css 里设置背景图片,使用方式与普通 web
项目大体相同,但需要注意以下几点:
- 支持 base64 格式图片。
- 支持网络路径图片。
- 小程序不支持在 css 中使用本地文件,包括本地的背景图和字体文件。需以 base64 方式方可使用。
- 使用本地路径背景图片需注意:
- 为方便开发者,在背景图片小于 40kb 时,
uni-app
编译到不支持本地背景图的平台时,会自动将其转化为 base64 格式; - 图片大于等于 40kb,会有性能问题,不建议使用太大的背景图,如开发者必须使用,则需自己将其转换为 base64 格式使用,或将其挪到服务器上,从网络地址引用。
- 本地背景图片的引用路径推荐使用以 ~@ 开头的绝对路径。
- 为方便开发者,在背景图片小于 40kb 时,
.test2 {background-image: url('~@/static/logo.png');
}
- 微信小程序不支持相对路径(真机不支持,开发工具支持)
2.11 字体图标
uni-app
支持使用字体图标,使用方式与普通 web
项目相同,需要注意以下几点:
- 支持 base64 格式字体图标。
- 支持网络路径字体图标。
- 小程序不支持在 css 中使用本地文件,包括本地的背景图和字体文件。需以 base64 方式方可使用。
- 网络路径必须加协议头
https
。 - 从 http://www.iconfont.cn 上拷贝的代码,默认是没加协议头的。
- 从 http://www.iconfont.cn 上下载的字体文件,都是同名字体(字体名都叫 iconfont,安装字体文件时可以看到),在 nvue 内使用时需要注意,此字体名重复可能会显示不正常,可以使用工具修改。
- 使用本地路径图标字体需注意:
- 为方便开发者,在字体文件小于 40kb 时,
uni-app
会自动将其转化为 base64 格式; - 字体文件大于等于 40kb,仍转换为 base64 方式使用的话可能有性能问题,如开发者必须使用,则需自己将其转换为 base64 格式使用,或将其挪到服务器上,从网络地址引用;
- 字体文件的引用路径推荐使用以 ~@ 开头的绝对路径。
- 为方便开发者,在字体文件小于 40kb 时,
@font-face {font-family: test1-icon;src: url('~@/static/iconfont.ttf');
}
nvue
中不可直接使用 css 的方式引入字体文件,需要使用以下方式在 js 内引入。nvue 内不支持本地路径引入字体,请使用网络链接或者base64
形式。src
字段的url
的括号内一定要使用单引号。
var domModule = weex.requireModule('dom');
domModule.addRule('fontFace', {fontFamily: 'fontFamilyName',src: "url('https://...')",
});
<template><view><view><text class="test"></text><text class="test"></text><text class="test"></text></view></view>
</template>
<style>@font-face {font-family: 'iconfont';src: url('https://at.alicdn.com/t/font_865816_17gjspmmrkti.ttf') format('truetype');}.test {font-family: iconfont;margin-left: 20rpx;}
</style>