简体中文
uni-app x的vue规范,按照vue3规范实现,从4.0起支持组合式写法。
本文暂时只包括兼容性表格,vue功能详情另见 vue3概述、Vue3 API。
uni-app x中vue的用法,有单独的示例应用:hello uvue。这里都是可以跑通的使用样例代码。
Android | iOS | web | |
---|---|---|---|
createApp() | √ | 4.11 | 4.0 |
createSSRApp() | √ | 4.11 | 4.0 |
app.mount() | √ | 4.11 | 4.0 |
app.unmount() | √ | 4.11 | 4.0 |
app.component() | √ | 4.11 | 4.0 |
app.directive() | - | - | - |
app.use() | 3.99 | 4.11 | 4.0 |
app.mixin() | 3.99 | 4.11 | 4.0 |
app.provide() | 3.99 | 4.11 | 4.0 |
app.runWithContext() | - | - | - |
app.version | √ | 4.11 | 4.0 |
app.config | - | - | - |
app.config.errorHandler | x | 4.11 | 4.0 |
app.config.warnHandler | - | - | - |
app.config.performance | - | - | - |
app.config.compilerOptions | - | - | - |
app.config.globalProperties | 3.99 | 4.11 | 4.0 |
app.config.optionMergeStrategies | - | - | - |
注意:
app.use
支持通过对象字面量、函数及 definePlugin
方式定义插件。app
的类型需要指定为 VueApp
。// main.uts
export function createApp() {
const app = createSSRApp(App)
// 通过对象字面量方式注册插件
app.use({
install(app) {
app.config.globalProperties.plugin1 = "plugin1"
}
})
// 通过函数方式注册插件
app.use(function (app) {
app.config.globalProperties.plugin2 = "plugin2"
})
// 通过 definePlugin + 对象字面量方式注册插件
const plugin3= definePlugin({
install(app) {
app.config.globalProperties.plugin3 = "plugin3"
}
})
app.use(plugin3)
// 通过 definePlugin + 函数方式注册插件
const plugin4= definePlugin(function (app) {
app.config.globalProperties.plugin4 = "plugin4"
})
app.use(plugin4)
// 注册插件时传递参数
// 注意:当传递插件参数时,app 的类型需要指定为 VueApp
app.use(function (app: VueApp, arg1:string, arg2:string) {
app.config.globalProperties.plugin5 = `${arg1}-${arg2}`
}, "arg1", "arg2");
}
globalProperties
是一个保留关键字,因此在项目中请勿声明名为 globalProperties
的变量。globalProperties
注册方法时,请使用直接函数表达式方式进行赋值。不支持先声明函数,再将其注册到 globalProperties
上的方式。同时,注册的函数一旦被赋值,不允许进行修改。globalProperties
在编译时处理,因此确保你的操作在编译时是可知的。例如,将变量赋值给 globalProperties
时,这个变量在编译时必须是已知的,而不能是在运行时才能确定的变量。Android | iOS | web | |
---|---|---|---|
version | √ | 4.11 | 4.0 |
nextTick() | √ | 4.11 | 4.0 |
defineComponent() | x | x | 4.0 |
defineAsyncComponent() | - | - | - |
defineCustomElement() | - | - | - |
目前 nextTick 可以保证当前数据已经同步到 DOM,但是由于排版和渲染是异步的的,所以 nextTick 不能保证 DOM 排版以及渲染完毕。如果需要获取排版后的节点信息推荐使用 uni.createSelectorQuery 不推荐直接使用 Element 对象。在修改 DOM 后,立刻使用 Element 对象的同步接口获取 DOM 状态可能获取到的是排版之前的,而 uni.createSelectorQuery 可以保障获取到的节点信息是排版之后的。
注意:
<script setup>
和 <script>
同时使用,如果需要配置 options
内容,比如 name
,可以使用 defineOptions
。await
。<script setup>
配置 generic
泛型类型参数。App.uvue
暂不支持组合式 API。Android | iOS | web | |
---|---|---|---|
ref() | √ | 4.11 | 4.0 |
computed() | - | - | - |
reactive() | √ | 4.11 | 4.0 |
readonly() | 4.0 | 4.11 | 4.0 |
watchEffect() | 4.0 | 4.11 | 4.0 |
watchPostEffect() | 4.0 | 4.11 | 4.0 |
watchSyncEffect() | 4.0 | 4.11 | 4.0 |
watch() | 4.0 | 4.11 | 4.0 |
注意:
computed
需通过泛型指定返回值类型。const count = ref(0)
const doubleCount = computed<number>(() : number => {
return count.value * 2
})
Android | iOS | web | |
---|---|---|---|
isRef() | 4.0 | 4.11 | 4.0 |
unref() | 4.0 | 4.11 | 4.0 |
toRef() | 4.0 | 4.11 | 4.11 |
toValue() | 4.0 | 4.11 | 4.11 |
toRefs() | 4.0 | 4.11 | 4.11 |
isProxy() | 4.0 | 4.11 | 4.0 |
isReactive() | 4.0 | 4.11 | 4.0 |
isReadonly() | 4.0 | 4.11 | 4.0 |
注意:
toRefs
仅支持 Array
和 UTSJSONObject
, 不支持自定义类型。Android | iOS | web | |
---|---|---|---|
shallowRef() | 4.0 | 4.11 | 4.0 |
triggerRef() | 4.0 | 4.11 | x |
customRef() | 4.0 | 4.11 | 4.0 |
shallowReactive() | 4.0 | 4.11 | 4.0 |
shallowReadonly() | 4.0 | 4.11 | 4.0 |
toRaw() | 4.0 | 4.11 | 4.0 |
markRaw() | - | - | - |
effectScope() | 4.0 | 4.11 | 4.0 |
getCurrentScope() | 4.0 | 4.11 | 4.0 |
onScopeDispose() | 4.0 | 4.11 | 4.0 |
Android | iOS | web | |
---|---|---|---|
onMounted() | 4.0 | 4.11 | 4.0 |
onUpdated() | 4.0 | 4.11 | 4.0 |
onUnmounted() | 4.0 | 4.11 | 4.0 |
onBeforeMount() | 4.0 | 4.11 | 4.0 |
onBeforeUpdate() | 4.0 | 4.11 | 4.0 |
onBeforeUnmount() | 4.0 | 4.11 | 4.0 |
onErrorCaptured() | - | - | - |
onRenderTracked() | - | - | - |
onRenderTriggered() | - | - | - |
onActivated() | x | x | 4.0 |
onDeactivated() | x | x | 4.0 |
onServerPrefetch() | - | - | - |
<template>
<!-- #ifdef APP -->
<scroll-view style="flex:1" :bounces="false">
<!-- #endif -->
<view class="page container">
<text>page lifecycle</text>
<button class="uni-common-mt" @click="scrollToBottom">scrollToBottom</button>
</view>
<!-- #ifdef APP -->
</scroll-view>
<!-- #endif -->
</template>
<script setup>
import { state, setLifeCycleNum } from '@/store/index.uts'
const isScrolled = ref(false)
onLoad((_: OnLoadOptions) => {
// 自动化测试
setLifeCycleNum(state.lifeCycleNum + 100)
})
onPageShow(() => {
// 自动化测试
setLifeCycleNum(state.lifeCycleNum + 10)
})
onReady(() => {
// 自动化测试
setLifeCycleNum(state.lifeCycleNum + 10)
})
onPullDownRefresh(() => {
// 自动化测试
setLifeCycleNum(state.lifeCycleNum + 10)
})
onPageScroll((_) => {
// 自动化测试
isScrolled.value = true
})
onReachBottom(() => {
// 自动化测试
setLifeCycleNum(state.lifeCycleNum + 10)
})
onBackPress((_: OnBackPressOptions): boolean | null => {
// 自动化测试
setLifeCycleNum(state.lifeCycleNum - 10)
return null
})
onPageHide(() => {
// 自动化测试
setLifeCycleNum(state.lifeCycleNum - 10)
})
onUnload(() => {
// 自动化测试
setLifeCycleNum(state.lifeCycleNum - 100)
})
onResize((_) => {
// 自动化测试
setLifeCycleNum(state.lifeCycleNum + 10)
})
// 自动化测试
const getLifeCycleNum = () : number => {
return state.lifeCycleNum
}
// 自动化测试
const pageSetLifeCycleNum = (num: number) => {
setLifeCycleNum(num)
}
// 自动化测试
const pullDownRefresh = () => {
uni.startPullDownRefresh({
success() {
setTimeout(() => {
uni.stopPullDownRefresh()
}, 1500)
},
})
}
const scrollToBottom = () => {
uni.pageScrollTo({
scrollTop: 2000,
})
}
// 自动化测试
const getIsScrolled = (): boolean => {
return isScrolled.value
}
defineExpose({
getLifeCycleNum,
pageSetLifeCycleNum,
pullDownRefresh,
scrollToBottom,
getIsScrolled
})
</script>
<style>
.container {
height: 1200px;
}
</style>
<template>
<!-- #ifdef APP -->
<scroll-view style="flex:1">
<!-- #endif -->
<view class="pag container">
<text class="uni-common-mb">component lifecycle</text>
<component-lifecycle class="component-lifecycle" @updateIsScroll="updateIsScroll" />
<button class="uni-common-mt" @click="scrollToBottom">scrollToBottom</button>
</view>
<!-- #ifdef APP -->
</scroll-view>
<!-- #endif -->
</template>
<script setup>
import ComponentLifecycle from '@/components/CompositionAPILifecycle.uvue'
import { state, setLifeCycleNum } from '@/store/index.uts'
const isScrolled = ref(false)
// 自动化测试
const getLifeCycleNum = () : number => {
return state.lifeCycleNum
}
// 自动化测试
const pageSetlifeCycleNum = (num : number) => {
setLifeCycleNum(num)
}
// 自动化测试
const pullDownRefresh = () => {
uni.startPullDownRefresh({
success() {
setTimeout(() => {
uni.stopPullDownRefresh()
}, 1500)
},
})
}
const scrollToBottom = () => {
uni.pageScrollTo({
scrollTop: 3000,
})
}
const updateIsScroll = (val : boolean) => {
isScrolled.value = val
}
// 自动化测试
const getIsScrolled = () : boolean => {
return isScrolled.value
}
defineExpose({
getLifeCycleNum,
pageSetlifeCycleNum,
pullDownRefresh,
scrollToBottom,
getIsScrolled
})
</script>
<style>
.container {
height: 1200px;
}
</style>
Android | iOS | web | |
---|---|---|---|
v-text | x | x | 4.0 |
v-html | 3.99 | x | 4.0 |
v-show | 3.9 | 4.11 | 4.0 |
v-if | 3.9 | 4.11 | 4.0 |
v-else | 3.9 | 4.11 | 4.0 |
v-else-if | 3.9 | 4.11 | 4.0 |
v-for | 3.9 | 4.11 | 4.0 |
v-on | 3.9 | 4.11 | 4.0 |
v-bind | 3.9 | 4.11 | 4.0 |
v-model | 3.9 | 4.11 | 4.0 |
v-slot | 3.9 | 4.11 | 4.0 |
v-pre | 3.99 | 4.11 | 4.0 |
v-once | 3.99 | 4.11 | x |
v-memo | 3.99 | 4.11 | x |
v-cloak | x | x | 4.0 |
注意:
App-android
平台,v-html
指令通过编译为 rich-text 组件实现。因此,v-html
指令的内容必须是 rich-text
支持的格式, 并且要遵循标签嵌套规则,例如, swiper
标签内只允许嵌套 swiper-item
标签。rich-text
组件不支持 class
样式,v-html
指令中同样不支持 class
样式。v-html
的标签内的内容会被忽略,v-html
指令的内容会编译为 rich-text
组件渲染为该标签的子节点。stop
和 once
。export default {}
方式定义组件。data
仅支持函数返回对象字面量方式。<script lang="uts">
export default {
data() {
return {
// 必须写这里
}
}
}
</script>
uni-app x
支持绑定 UTSJSONObject
和 Map
类型数据。在App-Android平台上 Map
的性能高于 UTSJSONObject
数据类型。从 uni-app x 4.01
起,Web平台也支持了 Map
类型绑定。
<template>
<view>
<view :style="styleMap" :class="classMap"></view>
</view>
</template>
<script lang="uts">
export default {
data() {
return {
styleMap: new Map<string, string>([['border', '2px solid red'], ['background-color', 'green']]),
classMap: new Map<string, boolean>([['w-100', true], ['h-100', true], ['rounded', false]])
}
}
}
</script>
<style>
.w-100 {
width: 100px;
}
.h-100 {
height: 100px;
}
.rounded {
border-radius: 8px;
}
</style>
App | Web |
---|---|
x | 4.0 |
处于 scoped
样式中的选择器如果想要做更“深度”的选择,也即:影响到子组件,可以使用 :deep()
这个伪类:
<style scoped>
.a :deep(.b) {
/* ... */
}
</style>
App | Web |
---|---|
x | 4.0 |
一个 <style module>
标签会被编译为 CSS Modules
并且将生成的 CSS class 作为 $style
对象暴露给组件:
<template>
<text :class="$style.red">This should be red</text>
</template>
<style module>
.red {
color: red;
}
</style>
得出的 class 将被哈希化以避免冲突,实现了同样的将 CSS 仅作用于当前组件的效果。
自定义注入名称
你可以通过给 module
attribute 一个值来自定义注入 class 对象的属性名:
<template>
<text :class="classes.red">red</text>
</template>
<style module="classes">
.red {
color: red;
}
</style>
与组合式 API 一同使用
可以通过 useCssModule
API 在 setup()
和 <script setup>
中访问注入的 class。对于使用了自定义注入名称的 <style module>
块,useCssModule 接收一个匹配的 module attribute 值作为第一个参数:
import { useCssModule } from 'vue'
// 在 setup() 作用域中...
// 默认情况下, 返回 <style module> 的 class
useCssModule()
// 具名情况下, 返回 <style module="classes"> 的 class
useCssModule('classes')
App | Web |
---|---|
x | 4.13+ |
单文件组件的 <style>
标签支持使用 v-bind
CSS 函数将 CSS 的值链接到动态的组件状态:
<template>
<text class="text">hello</text>
</template>
<script>
export default {
data() {
return {
color: 'red'
}
}
}
</script>
<style>
.text {
color: v-bind(color);
}
</style>
这个语法同样也适用于 <script setup>
,且支持 UTS 表达式 (需要用引号包裹起来):
<script setup>
const theme = {
color: 'red'
}
</script>
<template>
<text class="view">hello</text>
</template>
<style scoped>
.text {
color: v-bind('theme.color');
}
</style>
uni-app x 新增了 onLastPageBackPress 和 onExit 应用级生命周期,Android退出应用逻辑写在app.uvue里,新建项目的模板自动包含相关代码。如需修改退出逻辑,请直接修改相关代码。
注意
scroll-view
标签。Android | iOS | web |
---|---|---|
3.9 | 4.11 | 4.0 |
名称 | 类型 | 默认值 | 描述 | ||||
---|---|---|---|---|---|---|---|
setup | Any | - | - | ||||
lang | Any | - | |||||
|
Android | iOS | web | |
---|---|---|---|
uts | 4.0 | 4.11 | 4.0 |
Android | iOS | web | |
---|---|---|---|
setup | 4.0 | 4.11 | 4.0 |
lang | 4.0 | 4.11 | 4.0 |
Android | iOS | web |
---|---|---|
3.9 | 4.11 | 4.0 |
名称 | 类型 | 默认值 | 描述 | ||||||
---|---|---|---|---|---|---|---|---|---|
lang | string | - | |||||||
|
Android | iOS | web | |
---|---|---|---|
lang | 3.9 | x | 4.0 |
组件类型:string
<slot> 元素作为组件模板之中的内容分发插槽。<slot> 元素自身将被替换。
Android | iOS | web |
---|---|---|
3.9 | 4.11 | 4.0 |
名称 | 类型 | 默认值 | 描述 |
---|---|---|---|
name | string | - | 用于命名插槽。 |
Android | iOS | web |
---|---|---|
3.9 | 4.11 | 4.0 |
名称 | 类型 | 默认值 | 描述 | ||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
lang | Any | - | |||||||||
| |||||||||||
scoped | Any | - | - | ||||||||
module | Any | - | - |
Android | iOS | web | |
---|---|---|---|
lang | 3.9 | 4.11 | 4.0 |
scoped | x | x | 4.0 |
module | x | x | 4.0 |
组件类型:string
<keep-alive> 包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。和 <transition> 相似,<keep-alive> 是一个抽象组件:它自身不会渲染一个 DOM 元素,也不会出现在父组件链中。
Android | iOS | web |
---|---|---|
4.0 | 4.11 | 4.0 |
名称 | 类型 | 默认值 | 描述 |
---|---|---|---|
include | string | - | 字符串或正则表达式。只有名称匹配的组件会被缓存。 |
exclude | string | - | 字符串或正则表达式。任何名称匹配的组件都不会被缓存。 |
max | string | - | 最多可以缓存多少组件实例。 |
组件类型:string
渲染一个“元组件”为动态组件。依 is 的值,来决定哪个组件被渲染。
Android | iOS | web |
---|---|---|
3.99 | 4.11 | 4.0 |
名称 | 类型 | 默认值 | 描述 |
---|---|---|---|
is | Any | - | - |
inline-template | Any | - | - |
组件类型:string
<transition> 元素作为单个元素/组件的过渡效果。<transition> 只会把过渡效果应用到其包裹的内容上,而不会额外渲染 DOM 元素,也不会出现在检测过的组件层级中。
Android | iOS | web |
---|---|---|
x | x | 4.0 |
名称 | 类型 | 默认值 | 描述 | ||||||
---|---|---|---|---|---|---|---|---|---|
name | string | - | 用于自动生成 CSS 过渡类名。例如:name: 'fade' 将自动拓展为.fade-enter,.fade-enter-active等。默认类名为 "v" | ||||||
appear | string(true | false) | - | 是否在初始渲染时使用过渡。默认为 false。 | ||||||
css | string(true | false) | - | 是否使用 CSS 过渡类。默认为 true。如果设置为 false,将只通过组件事件触发注册的 JavaScript 钩子。 | ||||||
type | string | - | 指定过渡事件类型,侦听过渡何时结束。有效值为 "transition" 和 "animation"。默认 Vue.js 将自动检测出持续时间长的为过渡事件类型。 | ||||||
| |||||||||
mode | string | - | 控制离开/进入的过渡时间序列。有效的模式有 "out-in" 和 "in-out";默认同时生效。 | ||||||
| |||||||||
duration | string | - | 指定过渡的持续时间。默认情况下,Vue 会等待过渡所在根元素的第一个 transitionend 或 animationend 事件。 | ||||||
enter-class | Any | - | - | ||||||
leave-class | Any | - | - | ||||||
appear-class | Any | - | - | ||||||
enter-to-class | Any | - | - | ||||||
leave-to-class | Any | - | - | ||||||
appear-to-class | Any | - | - | ||||||
enter-active-class | Any | - | - | ||||||
leave-active-class | Any | - | - | ||||||
appear-active-class | Any | - | - | ||||||
@before-enter | Any | - | - | ||||||
@before-leave | Any | - | - | ||||||
@before-appear | Any | - | - | ||||||
@enter | Any | - | - | ||||||
@leave | Any | - | - | ||||||
@appear | Any | - | - | ||||||
@after-enter | Any | - | - | ||||||
@after-leave | Any | - | - | ||||||
@after-appear | Any | - | - | ||||||
@enter-cancelled | Any | - | - | ||||||
@leave-cancelled | string | - | v-show only | ||||||
@appear-cancelled | Any | - | - |
组件类型:string
<transition-group> 元素作为多个元素/组件的过渡效果。<transition-group> 渲染一个真实的 DOM 元素。默认渲染 <span>,可以通过 tag 属性配置哪个元素应该被渲染。
Android | iOS | web |
---|---|---|
x | x | 4.0 |
名称 | 类型 | 默认值 | 描述 | ||||||
---|---|---|---|---|---|---|---|---|---|
tag | string | - | 默认为 span。 | ||||||
move-class | string | - | 覆盖移动过渡期间应用的 CSS 类。 | ||||||
name | string | - | 用于自动生成 CSS 过渡类名。例如:name: 'fade' 将自动拓展为.fade-enter,.fade-enter-active等。默认类名为 "v" | ||||||
appear | string(true | false) | - | 是否在初始渲染时使用过渡。默认为 false。 | ||||||
css | string(true | false) | - | 是否使用 CSS 过渡类。默认为 true。如果设置为 false,将只通过组件事件触发注册的 JavaScript 钩子。 | ||||||
type | string | - | 指定过渡事件类型,侦听过渡何时结束。有效值为 "transition" 和 "animation"。默认 Vue.js 将自动检测出持续时间长的为过渡事件类型。 | ||||||
| |||||||||
mode | Any | - | - | ||||||
duration | string | - | 指定过渡的持续时间。默认情况下,Vue 会等待过渡所在根元素的第一个 transitionend 或 animationend 事件。 | ||||||
enter-class | Any | - | - | ||||||
leave-class | Any | - | - | ||||||
appear-class | Any | - | - | ||||||
enter-to-class | Any | - | - | ||||||
leave-to-class | Any | - | - | ||||||
appear-to-class | Any | - | - | ||||||
enter-active-class | Any | - | - | ||||||
leave-active-class | Any | - | - | ||||||
appear-active-class | Any | - | - | ||||||
@before-enter | Any | - | - | ||||||
@before-leave | Any | - | - | ||||||
@before-appear | Any | - | - | ||||||
@enter | Any | - | - | ||||||
@leave | Any | - | - | ||||||
@appear | Any | - | - | ||||||
@after-enter | Any | - | - | ||||||
@after-leave | Any | - | - | ||||||
@after-appear | Any | - | - | ||||||
@enter-cancelled | Any | - | - | ||||||
@leave-cancelled | string | - | v-show only | ||||||
@appear-cancelled | Any | - | - |
组件类型:string
Teleport 提供了一种干净的方法,允许我们控制在 DOM 中哪个父节点下呈现 HTML,而不必求助于全局状态或将其拆分为两个组件。
Android | iOS | web |
---|---|---|
4.0 | 4.11 | 4.0 |
名称 | 类型 | 默认值 | 描述 |
---|---|---|---|
to | string | - | 必须是有效的查询选择器或 HTMLElement (如果在浏览器环境中使用)。指定将在其中移动 <teleport> 内容的目标元素 |
disabled | boolean | - | 此可选属性可用于禁用 <teleport> 的功能,这意味着其插槽内容将不会移动到任何位置,而是在您在周围父组件中指定了 <teleport> 的位置渲染。 |
注意:
to
属性。Android | iOS | web | |
---|---|---|---|
key | 3.9 | 4.11 | 4.0 |
ref | 3.9 | 4.11 | 4.0 |
is | 3.99 | 4.11 | 4.0 |
Android | iOS | web | |
---|---|---|---|
beforeCreate | 3.9 | 4.11 | 4.0 |
created | 3.9 | 4.11 | 4.0 |
beforeMount | 3.9 | 4.11 | 4.0 |
mounted | 3.9 | 4.11 | 4.0 |
beforeUpdate | 3.9 | 4.11 | 4.0 |
updated | 3.9 | 4.11 | 4.0 |
beforeUnmount | 3.9 | 4.11 | 4.0 |
unmounted | 3.9 | 4.11 | 4.0 |
errorCaptured | x | x | 4.0 |
renderTracked | x | x | 4.0 |
renderTriggered | x | x | 4.0 |
activated | 4.0 | 4.11 | 4.0 |
deactivated | 4.0 | 4.11 | 4.0 |
serverPrefetch | - | - | - |
<template>
<!-- #ifdef APP -->
<scroll-view style="flex: 1" :bounces="false">
<!-- #endif -->
<view class="page container">
<text>page lifecycle</text>
<button class="uni-common-mt" @click="scrollToBottom">scrollToBottom</button>
</view>
<!-- #ifdef APP -->
</scroll-view>
<!-- #endif -->
</template>
<script lang="uts">
import { state, setLifeCycleNum } from '@/store/index.uts'
export default {
data() {
return {
isScrolled: false,
}
},
onLoad(_ : OnLoadOptions) {
// 自动化测试
setLifeCycleNum(state.lifeCycleNum + 100)
},
onShow() {
// 自动化测试
setLifeCycleNum(state.lifeCycleNum + 10)
},
onReady() {
// 自动化测试
setLifeCycleNum(state.lifeCycleNum + 10)
},
onPullDownRefresh() {
// 自动化测试
setLifeCycleNum(state.lifeCycleNum + 10)
},
onPageScroll(_) {
// 自动化测试
this.isScrolled = true
},
onReachBottom() {
// 自动化测试
setLifeCycleNum(state.lifeCycleNum + 10)
},
onBackPress(_ : OnBackPressOptions) : boolean | null {
// 自动化测试
setLifeCycleNum(state.lifeCycleNum - 10)
return null
},
onHide() {
// 自动化测试
setLifeCycleNum(state.lifeCycleNum - 10)
},
onUnload() {
// 自动化测试
setLifeCycleNum(state.lifeCycleNum - 100)
},
onResize(_){
// 自动化测试
setLifeCycleNum(state.lifeCycleNum + 10)
},
methods: {
// 自动化测试
getLifeCycleNum() : number {
return state.lifeCycleNum
},
// 自动化测试
setLifeCycleNum(num : number) {
setLifeCycleNum(num)
},
// 自动化测试
pullDownRefresh() {
uni.startPullDownRefresh({
success() {
setTimeout(() => {
uni.stopPullDownRefresh()
// 一秒后立即停止下拉刷新不会触发 onPullDownRefresh,因为下拉动画时间大概需要1.1~1.2秒
}, 1500)
},
})
},
scrollToBottom() {
uni.pageScrollTo({
scrollTop: 2000,
})
},
},
}
</script>
<style>
.container {
height: 1200px;
}
</style>
<template>
<view class="page">
<text class="uni-common-mb">component lifecycle</text>
<component-lifecycle class="component-lifecycle" />
</view>
</template>
<script>
import ComponentLifecycle from '@/components/OptionsAPILifecycle.uvue'
import { state } from '@/store/index.uts'
export default {
components: { ComponentLifecycle },
methods: {
// 自动化测试
getLifeCycleNum(): number {
return state.lifeCycleNum
},
},
}
</script>
目前 mounted、unmounted 可以保证当前数据已经同步到 DOM,但是由于排版和渲染是异步的的,所以 mounted、unmounted 不能保证 DOM 排版以及渲染完毕。如果需要获取排版后的节点信息推荐使用 uni.createSelectorQuery 不推荐直接使用 Element 对象。在修改 DOM 后,立刻使用 Element 对象的同步接口获取 DOM 状态可能获取到的是排版之前的,而 uni.createSelectorQuery 可以保障获取到的节点信息是排版之后的。
暂不支持vue插件,比如pinia、vuex、i18n、router。简单的状态管理可以参考文档全局变量和状态管理。
Android | iOS | web | |
---|---|---|---|
data | 3.9 | 4.11 | 4.0 |
props | 3.9 | 4.11 | 4.0 |
computed | 3.9 | 4.11 | 4.0 |
methods | 3.9 | 4.11 | 4.0 |
watch | 3.9 | 4.11 | 4.0 |
emits | 3.9 | 4.11 | 4.0 |
expose | x | x | 4.0 |
注意: |
watch immediate
第一次调用时,App-Android 平台旧值为初始值,web 平台为 null。Android | iOS | web | |
---|---|---|---|
template | - | - | - |
render | 3.9 | 4.11 | 4.0 |
compilerOptions | - | - | - |
slots | 3.9 | 4.11 | 4.0 |
Android | iOS | web | |
---|---|---|---|
provide | 3.99 | 4.11 | 4.0 |
inject | 3.99 | 4.11 | 4.0 |
mixins | 3.99 | 4.11 | 4.0 |
extends | - | - | - |
注意:
inject
声明从上层提供方注入的属性时,支持两种写法:字符串数组和对象。推荐使用对象写法,因为当使用数组方法时,类型会被推导为 any | null
类型。type
属性用于标记类型。如果注入的属性类型不是基础数据类型,需要通过 PropType
来标记类型。export default {
inject: {
provideString: {
type: String,
default: 'default provide string value'
},
provideObject: {
type: Object as PropType<UTSJSONObject>
},
provideMap: {
type: Object as PropType<Map<string, string>>,
default: (): Map<string, string> => {
return new Map<string, string>([['key', 'default provide map value']])
}
}
}
}
mixins
仅支持通过字面量对象方式和 defineMixin
函数方式定义。const mixin1 = defineMixin({
onLoad() {
console.log('mixin1 onLoad')
}
})
export default {
mixins: [
mixin1,
{
data() {
return {
mixin2: 'mixin2'
}
}
}
]
}
同名属性会被覆盖,同名生命周期会依次执行。
同名属性的优先级如下:
app.mixin
内嵌入的 mixin < 在 app.mixin
中声明的 mixin < 在 page.mixin
内嵌入的 mixin < 在 page.mixin
中声明的 mixin < 在 component.mixin
内嵌入的 mixin < 在 component.mixin
中声明的 mixin同名生命周期的执行顺序如下:
app.mixin
内嵌入的 mixinapp.mixin
中声明的 mixinpage.mixin
内嵌入的 mixinpage.mixin
中声明的 mixincomponent.mixin
内嵌入的 mixincomponent.mixin
中声明的 mixinAndroid | iOS | web | |
---|---|---|---|
name | 3.9 | 4.11 | 4.0 |
inheritAttrs | 3.9 | 4.11 | 4.0 |
components | 3.9 | 4.11 | 4.0 |
directives | - | - | - |
Android | iOS | web | |
---|---|---|---|
$data | √ | 4.11 | 4.0 |
$props | √ | 4.11 | 4.0 |
$el | √ | 4.11 | 4.0 |
$options | √ | 4.11 | 4.0 |
$parent | √ | 4.11 | 4.0 |
$root | √ | 4.11 | 4.0 |
$slots | √ | 4.11 | 4.0 |
$refs | √ | 4.11 | 4.0 |
$attrs | √ | 4.11 | 4.0 |
$watch() | √ | 4.11 | 4.0 |
$emit | √ | 4.11 | 4.0 |
$forceUpdate | √ | 4.11 | 4.0 |
$nextTick | √ | 4.11 | 4.0 |
$callMethod | √ | 4.11 | 4.0 |
目前 $nextTick 可以保证当前数据已经同步到 DOM,但是由于排版和渲染是异步的的,所以 $nextTick 不能保证 DOM 排版以及渲染完毕。如果需要获取排版后的节点信息推荐使用 uni.createSelectorQuery 不推荐直接使用 Element 对象。在修改 DOM 后,立刻使用 Element 对象的同步接口获取 DOM 状态可能获取到的是排版之前的,而 uni.createSelectorQuery 可以保障获取到的节点信息是排版之后的。
data内$开头的属性不可直接使用this.$xxx
访问,需要使用this.$data['$xxx']
,这是vue的规范。目前安卓端可以使用this.$xxx访问是Bug而非特性,请勿使用此特性。
示例
<template>
<view></view>
</template>
<script>
export default {
data() {
return {
$a: 1
}
},
onReady() {
console.log(this.$data['$a'] as number) // 1
}
}
</script>
Android | iOS | web | |
---|---|---|---|
h() | 3.99 | 4.11 | 4.0 |
mergeProps() | 4.0 | 4.11 | 4.0 |
cloneVNode() | 4.0 | 4.11 | 4.0 |
isVNode() | √ | 4.11 | 4.0 |
resolveComponent() | √ | 4.11 | 4.0 |
resolveDirective() | - | - | - |
withDirectives() | √ | 4.11 | 4.0 |
withModifiers() | √ | 4.11 | 4.0 |
Android | iOS | web | |
---|---|---|---|
defineProps() | 4.0 | 4.11 | 4.0 |
defineEmits() | 4.0 | 4.11 | 4.0 |
defineModel() | 4.0 | 4.11 | 4.11 |
defineExpose() | 4.0 | 4.11 | 4.0 |
defineOptions() | 4.0 | 4.11 | 4.11 |
defineSlots() | 4.0 | 4.11 | 4.0 |
useSlots() | 4.0 | 4.11 | 4.0 |
useAttrs() | 4.0 | 4.11 | 4.0 |
<template>
<!-- #ifdef APP -->
<scroll-view style="flex: 1">
<!-- #endif -->
<view class="page">
<text class='uni-common-mt' id="str">str: {{ str }}</text>
<text class='uni-common-mt' id="num">num: {{ num }}</text>
<text class='uni-common-mt' id="bool">bool: {{ bool }}</text>
<text class='uni-common-mt' id="count">count: {{count}}</text>
<button class='uni-common-mt' id="increment-btn" @click="increment">increment</button>
<text class='uni-common-mt' id="obj-str">obj.str: {{ obj['str'] }}</text>
<text class='uni-common-mt' id="obj-num">obj.num: {{ obj['num'] }}</text>
<text class='uni-common-mt' id="obj-bool">obj.bool: {{ obj['bool'] }}</text>
<button class='uni-common-mt' id="update-obj-btn" @click="updateObj">update obj</button>
<!-- #ifdef APP -->
<RenderFunction :str='str' :count='count' :obj='obj' @compUpdateObj='compUpdateObj' :isShow='true' />
<!-- #endif -->
<Foo>
<text class="uni-common-mt" id="default-slot-in-foo">default slot in Foo</text>
</Foo>
</view>
<!-- #ifdef APP -->
</scroll-view>
<!-- #endif -->
</template>
<script>
// #ifdef APP
import RenderFunction from './RenderFunction.uvue'
// #endif
import Foo from './Foo.uvue'
export default {
components: {
// #ifdef APP
RenderFunction,
// #endif
Foo
},
setup() {
const count = ref(0)
// 函数只能通过声明变量,赋值函数的方式,不支持 function xxx(){}
const increment = () => { count.value++ }
const obj = reactive({
str: 'obj default str',
num: 0,
bool: false,
})
const updateObj = () => {
obj['str'] = 'obj new str'
obj['num'] = 100
obj['bool'] = true
}
const compUpdateObj = () => {
obj['str'] = 'obj new str by comp update'
obj['num'] = 200
obj['bool'] = true
}
return {
str: 'default str',
num: 0,
bool: false,
count,
increment,
obj,
updateObj,
compUpdateObj
}
}
}
</script>
注意:
defineProps
仅支持数组字面量、对象字面量定义(等同于 options
中的 props
规则)及使用纯类型参数的方式来声明。// 数组字面量
defineProps(['str', 'num', 'bool', 'arr', 'obj', 'fn'])
// 对象字面量
defineProps({
str: String,
num: Number,
bool: {
type: Boolean,
default: true
},
arr: {
type: Array as PropType<string[]>,
default: () : string[] => [] as string[]
},
obj: {
type: Object as PropType<UTSJSONObject>,
default: () : UTSJSONObject => ({ a: 1 })
},
fn: {
type: Function as PropType<() => string>,
default: () : string => ''
}
})
// 纯类型参数
defineProps<{
str : String,
num : Number,
bool : Boolean,
arr : PropType<string[]>,
obj : PropType<UTSJSONObject>,
fn : PropType<() => string>
}>()
defineEmits
仅支持数组字面量和纯类型参数的方式来声明。// 数组字面量
const emit = defineEmits(['change'])
// 纯类型参数
const emit = defineEmits<{
(e : 'change', id : number) : void
}>()
const emit = defineEmits<{
// 具名元组语法
change : [id: number]
}>()
defineOptions
仅支持对象字面量方式定义。defineOptions({
data() {
return {
count: 0,
price: 10,
total: 0
}
},
computed: {
doubleCount() : number {
return this.count * 2
},
},
watch: {
count() {
this.total = this.price * this.count
},
},
methods: {
increment() {
this.count++
}
}
})
defineExpose
仅支持对象字面量方式定义,导出的变量或方法,必须是 setup
中定义的,暂不支持外部定义。<script setup>
const str = 'str'
const num = ref(0)
const increment = () => {
num.value++
}
defineExpose({
str,
num,
increment
})
</script>
实现递归组件时不要使用组件import自身的写法,直接在模板内使用组件名即可。
// component-a.uvue
<template>
<view>
<text>component-a::{{text}}</text>
<component-a v-if="!end" :text="text" :limit="limit-1"></component-a>
</view>
</template>
<script>
// import componentA from './component-a' // 错误用法
export default {
name: "component-a",
props: {
text: {
type: String,
default: ''
},
limit: {
type: Number,
default: 2
}
},
computed: {
end() : boolean {
return this.limit <= 0
}
}
}
</script>