UniApp nvue 原生渲染
概述
uni-app App 端内置基于 weex 改进的原生渲染引擎。vue 页面使用 webview 渲染,nvue 页面(native vue)使用原生渲染。一个 App 中可以同时使用两种页面。
nvue 也可多端编译输出 H5 和小程序,但 css 写法受限,不开发 App 时不需要使用 nvue。
适用场景
- 高性能区域长列表或瀑布流滚动
- 复杂自定义下拉刷新
- 左右拖动长列表
- 区域滚动长列表 + 左右拖动 + 吸顶
- 软键盘右下角按钮改为"发送"
- 解决原生控件层级问题
- 深度使用 map 组件
- 深度使用 video 组件
- 直播推流
- 对 App 启动速度要求极致化
纯原生渲染模式
manifest.json 中配置 renderer: "native" 启用纯原生渲染,可减少包体积和内存占用。此时 vue 页面将被忽略。
编译模式
| weex 编译模式 | uni-app 编译模式 | |
|---|---|---|
| 平台 | 仅 App | 所有端 |
| 组件 | weex 组件如 div | uni-app 组件如 view |
| 生命周期 | weex 生命周期 | 所有 uni-app 生命周期 |
| JS API | weex API、uni API、Plus API | 同左 |
| 单位 | 750px 是屏幕宽度 | 750rpx 是屏幕宽度 |
| 全局样式 | 手动引入 | app.vue 即可 |
| 页面滚动 | 必须套组件 | 默认支持 |
在 manifest.json 中配置:
{
"app-plus": {
"nvueCompiler": "uni-app"
}
}{
"app-plus": {
"nvueCompiler": "uni-app"
}
}nvue vs vue 开发区别
- 显隐只可用
v-if,不可用v-show - 只能使用
flex布局,默认排列方向为column - 文字内容必须在
<text>组件下 - 只有
text标签可设置字体大小、颜色 - 不能使用百分比、媒体查询
- 不支持
background-image背景图 - css 选择器只支持 class 选择器
- class 绑定只支持数组语法
- Android 端各组件默认透明,需设置
background-color - Android 端大量圆角边框会造成性能问题
- 没有 bounce 回弹效果(list/waterfall 等组件除外)
- App.vue 中定义的全局 js 变量在 nvue 不生效,globalData 和 vuex 生效
style中不能引入字体文件- 不支持 TypeScript
样式
盒模型
nvue 盒模型 box-sizing 默认为 border-box。Android 仅支持 overflow:hidden,iOS 支持 hidden 和 visible。
Flexbox
Flexbox 是默认且唯一的布局模型,不需要手动设置 display: flex。不支持 flex-shrink、flex-basis、align-content 以及 flex 简写。
定位
Android 下定位元素超过容器边界将不可见(overflow 默认 hidden)。
伪类
| 参数 | 支持组件 |
|---|---|
| active | 所有组件 |
| focus | input、textarea |
| disabled | input、textarea |
| enabled | input、textarea |
线性渐变
background-image: linear-gradient(to bottom right, #AD18F9, #05DFC7);background-image: linear-gradient(to bottom right, #AD18F9, #05DFC7);只支持两种颜色渐变,不支持 radial-gradient(径向渐变)。background-image 优先级高于 background-color。
阴影
Android 平台设置 box-shadow 时需要让出阴影渲染位置(使用 margin)。
文本样式
- 只有
text标签可设置color、font-size font-weight支持:normal、bold 以及 100-900- iOS 支持 9 种,Android 仅支持 400 和 700
text-overflow支持 clip 和 ellipsis
API
DOM - addRule(加载自定义字体)
const domModule = uni.requireNativePlugin('dom')
domModule.addRule('fontFace', {
fontFamily: 'myIconfont',
src: "url('http://at.alicdn.com/t/font_xxx.ttf')",
})const domModule = uni.requireNativePlugin('dom')
domModule.addRule('fontFace', {
fontFamily: 'myIconfont',
src: "url('http://at.alicdn.com/t/font_xxx.ttf')",
})DOM - scrollToElement
const dom = uni.requireNativePlugin('dom')
dom.scrollToElement(this.$refs.item10, { offset: 0, animated: true })const dom = uni.requireNativePlugin('dom')
dom.scrollToElement(this.$refs.item10, { offset: 0, animated: true })DOM - getComponentRect
获取元素外框:
dom.getComponentRect(this.$refs.test, (res) => { console.log(res.size) })dom.getComponentRect(this.$refs.test, (res) => { console.log(res.size) })animation 动画
const animation = uni.requireNativePlugin('animation')
animation.transition(this.$refs.test, {
styles: { backgroundColor: '#007AFF', transform: 'translate(100px, 80px)' },
duration: 800,
timingFunction: 'ease',
delay: 0,
}, () => { /* 完成回调 */ })const animation = uni.requireNativePlugin('animation')
animation.transition(this.$refs.test, {
styles: { backgroundColor: '#007AFF', transform: 'translate(100px, 80px)' },
duration: 800,
timingFunction: 'ease',
delay: 0,
}, () => { /* 完成回调 */ })BindingX
BindingX 是原生解析的预描述交互语法,由原生处理视图层交互和动效,减少通信损耗:
const Binding = uni.requireNativePlugin('bindingx')
Binding.bind({
eventType: 'timing',
exitExpression: 't>800',
props: [{
element: main_image,
property: 'transform.rotateZ',
expression: 'easeOutQuint(t,45,0-45,800)',
}],
}, (res) => { if (res.state === 'exit') Binding.unbind({ token: main_binding.token }) })const Binding = uni.requireNativePlugin('bindingx')
Binding.bind({
eventType: 'timing',
exitExpression: 't>800',
props: [{
element: main_image,
property: 'transform.rotateZ',
expression: 'easeOutQuint(t,45,0-45,800)',
}],
}, (res) => { if (res.state === 'exit') Binding.unbind({ token: main_binding.token }) })nvue 和 vue 通信
推荐使用 uni.$on / uni.$emit 进行页面通讯:
// 发送方
uni.$emit('page-popup', { title: 'title', content: 'content' })
// 接收方
uni.$on('page-popup', (data) => { console.log(data.title) })// 发送方
uni.$emit('page-popup', { title: 'title', content: 'content' })
// 接收方
uni.$on('page-popup', (data) => { console.log(data.title) })共享变量方案:
- vuex:自 HBuilderX 2.2.5 起 nvue 支持
- uni.storage:nvue 和 vue 共享
- globalData:全端通用
nvue 不支持的 uni-app API
| API | 说明 | 替代方案 |
|---|---|---|
| uni.createAnimation() | 创建动画实例 | animation 模块 |
| uni.pageScrollTo() | 页面滚动 | scrollToElement |
| uni.createIntersectionObserver() | 节点布局交互 | — |
iOS 平台注意
list、waterfall 组件内容不足时无法触发下拉刷新,可通过配置 alwaysScrollableVertical="true" 解决。
Cao Note