| 兼容性 | |
|---|---|
| v-text | |
| v-html | |
| v-show | |
| v-if | |
| v-else | |
| v-else-if | |
| v-for | |
| v-on | |
| v-bind | |
| v-model | |
| v-slot | |
| v-pre | |
| v-once | |
| v-memo | |
| v-cloak |
更新元素的文本内容。
期望的绑定值类型:string
详细信息
v-text 将覆盖元素中所有现有的内容。
示例 详情
组合式 API
选项式 API
<template>
<view class="page">
<view class="flex flex-row justify-between mb-10">
<text>v-txt for text:</text>
<text id="v-text-text" v-text="vTextForText"></text>
</view>
<view class="flex flex-row justify-between mb-10">
<text>v-txt for view:</text>
<view id="v-text-view" v-text="vTextForView"></view>
</view>
</view>
</template>
<script setup lang="uts">
const vTextForText = ref('v-text for text')
const vTextForView = ref('v-text for view')
</script>
更新元素的内容,并且不会被解析。
注意
在 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 组件渲染为该标签的子节点。
示例 详情
组合式 API
选项式 API
<template>
<view v-html="html" />
</template>
<script setup lang="uts">
const html = '<p class="p" style="color: red;">hello world for composition API!</p>'
</script>
基于表达式值的真假性,来改变元素的可见性。
示例 详情
组合式 API
选项式 API
<template>
<view class="page">
<button id="toggle-btn" @click="toggleShow">toggle show/hide</button>
<text>点击上方按钮,切换下方 view 显示/隐藏</text>
<text>show default true: {{dataInfo.showDefaultTrue}}</text>
<view class="mt-10 default-true" id="v-show-element-default-true" v-show="dataInfo.showDefaultTrue"></view>
<text>show default false: {{dataInfo.showDefaultFalse}}</text>
<view class="mt-10 default-false" id="v-show-element-default-false" v-show="dataInfo.showDefaultFalse"></view>
<Foo v-show="dataInfo.showDefaultFalse" />
</view>
</template>
<script setup lang="uts">
import Foo from './Foo.uvue'
type DataInfo = {
showDefaultTrue : boolean
showDefaultFalse : boolean
}
const dataInfo = reactive({
showDefaultTrue: true,
showDefaultFalse: false
} as DataInfo)
const toggleShow = () => {
dataInfo.showDefaultTrue = !dataInfo.showDefaultTrue
dataInfo.showDefaultFalse = !dataInfo.showDefaultFalse
}
defineExpose({
dataInfo
})
</script>
<style>
.default-true,
.default-false {
display: flex;
width: 100px;
height: 50px;
}
.default-true {
background-color: greenyellow;
}
.default-false {
background-color: antiquewhite;
}
</style>
基于表达式值的真假性,来条件性地渲染元素或者模板片段。
详细信息
当 v-if 元素被触发,元素及其所包含的指令/组件都会销毁和重构。如果初始条件是假,那么其内部的内容根本都不会被渲染。
可用于 <template> 表示仅包含文本或多个元素的条件块。
示例 详情
组合式 API
选项式 API
<template>
<!-- #ifdef APP && !VUE3-VAPOR -->
<scroll-view style="flex: 1">
<!-- #endif -->
<view class="page">
<view class="mb-10 flex justify-between flex-row">
<text>v-if</text>
<text id="v-if-show" v-if="show">show</text>
</view>
<button id="switch-v-if-btn" @click="show = !show">switch v-if</button>
<view class="mt-10 mb-10 flex justify-between flex-row">
<text>num:</text>
<text id="num">{{ num }}</text>
</view>
<view class="mb-10 flex justify-between flex-row">
<text>v-if v-else-if v-else</text>
<text id="num-v-if" v-if="num == 1">v-if num = 1</text>
<text id="num-v-else-if" v-else-if="num == 2">v-else-if num = 2</text>
<text id="num-v-else" v-else>v-else</text>
</view>
<button id="change-num-btn" @click="changeNum">change num</button>
<!-- 测试标题 -->
<view class="mt-10">
<text class="section-title">多层嵌套v-if测试</text>
</view>
<!-- view 普通版本 -->
<view class="mt-10">
<text class="test-label">1. view 普通版本 </text>
<view class="test-item" v-if="viewNormalChild1">
<view v-if="viewNormalChild1" id="view-normal-child1">
<text>view二层嵌套内容</text>
<view v-if="viewNormalChild2" id="view-normal-child2">
<text>view三层嵌套内容</text>
</view>
<button id="toggle-view-normal-child2" @click="viewNormalChild2 = !viewNormalChild2">内层切换显示</button>
</view>
</view>
<button id="toggle-view-normal-child1" @click="viewNormalChild1 = !viewNormalChild1">外层切换显示</button>
</view>
<!-- view 拍平版本 -->
<view class="mt-10">
<text class="test-label">2. view 拍平版本 </text>
<view class="test-item" v-if="viewFlattenChild1">
<view flatten v-if="viewFlattenChild1" id="view-flatten-child1">
<view flatten v-if="viewFlattenChild1">
<text>view拍平三层嵌套内容(应该能消失)</text>
</view>
</view>
</view>
<button id="toggle-view-flatten-child1" @click="viewFlattenChild1 = !viewFlattenChild1">
切换显示
</button>
</view>
<!-- text 普通版本 -->
<view class="mt-10">
<text class="test-label">3. text 普通版本 </text>
<view class="test-item">
<text v-if="textNormalChild1">
<text v-if="textNormalChild1" id="text-normal-child1">text二层嵌套内容(应该能消失)</text>
</text>
</view>
<button id="toggle-text-normal-child1" @click="textNormalChild1 = !textNormalChild1">
切换显示
</button>
</view>
<!-- text 拍平版本 -->
<view class="mt-10">
<text class="test-label">4. text 拍平版本 </text>
<view flatten class="test-item">
<text flatten v-if="textFlattenChild1">
<text flatten v-if="textFlattenChild1" id="text-flatten-child1">text拍平二层嵌套内容(应该能消失)</text>
</text>
</view>
<button id="toggle-text-flatten-child1" @click="textFlattenChild1 = !textFlattenChild1">
切换显示
</button>
</view>
<!-- image 普通版本 -->
<view class="mt-10">
<text class="test-label">5. image 普通版本 </text>
<view class="test-item">
<image v-if="imageNormalChild1" id="image-normal-child1" src="/static/logo.png" class="test-image"></image>
</view>
<button id="toggle-image-normal-child1" @click="imageNormalChild1 = !imageNormalChild1">
切换显示
</button>
</view>
<!-- image 拍平版本 -->
<view class="mt-10">
<text class="test-label">6. image 拍平版本(多层嵌套v-if)</text>
<view flatten class="test-item">
<image flatten v-if="imageFlattenChild1" id="image-flatten-child1" src="/static/logo.png" class="test-image"></image>
</view>
<button id="toggle-image-flatten-child1" @click="imageFlattenChild1 = !imageFlattenChild1">
切换显示
</button>
</view>
<!-- scroll-view:动态切换 -->
<view class="mt-10">
<text class="test-label">8. scroll-view(动态v-if)</text>
<view class="test-item">
<scroll-view v-if="scrollViewChild1" id="scroll-view-child1" class="scroll-view-test">
<text>scroll-view内容1(应该能消失)</text>
<view><text>scroll-view内容2(应该能消失)</text></view>
</scroll-view>
<button id="toggle-scroll-view-child1" @click="scrollViewChild1 = !scrollViewChild1">
切换scroll-view显示
</button>
</view>
</view>
<!-- 自定义 child 组件 -->
<view class="mt-10">
<text class="test-label">9. child 组件(子child动态v-if普通版本➕拍平版本)</text>
<view class="test-item">
<child v-if="childComponent1" id="child-component1"></child>
<view flatten>
<child v-if="childComponent1" id="child-component2" flatten></child>
</view>
<button id="toggle-child-component1" @click="childComponent1 = !childComponent1">
切换child组件显示
</button>
</view>
</view>
</view>
<!-- #ifdef APP && !VUE3-VAPOR -->
</scroll-view>
<!-- #endif -->
</template>
<script setup lang="uts">
import child from './child.uvue'
// 原有变量
const show = ref(true)
const num = ref(1)
// view 测试变量
const viewNormalChild1 = ref(true)
const viewNormalChild2 = ref(true)
const viewFlattenChild1 = ref(true)
// text 测试变量
const textNormalChild1 = ref(true)
const textFlattenChild1 = ref(true)
// image 测试变量
const imageNormalChild1 = ref(true)
const imageFlattenChild1 = ref(true)
// scroll-view 测试变量
const scrollViewChild1 = ref(true)
// child 组件测试变量
const childComponent1 = ref(true)
const changeNum = () => {
if(num.value<3) {
num.value++
} else {
num.value = 1
}
}
</script>
<style>
.section-title {
font-size: 16px;
font-weight: bold;
margin-bottom: 10px;
}
.test-label {
font-size: 14px;
color: #666;
margin-bottom: 5px;
}
.test-item {
padding: 10px;
background-color: #f5f5f5;
border-radius: 5px;
}
.test-image {
width: 50px;
height: 50px;
}
.scroll-view-test {
height: 100px;
background-color: #e0e0e0;
padding: 10px;
}
</style>
基于原始数据多次渲染元素或模板块。
期望的绑定值类型:Array | UTSJSONObject | number | string | Iterable
详细信息
指令值必须使用特殊语法 alias in expression 为正在迭代的元素提供一个别名:
<view v-for="item in items">
{{ item.text }}
</view>
v-for 的默认方式是尝试就地更新元素而不移动它们。要强制其重新排序元素,你需要用特殊 attribute key 来提供一个排序提示:
<view v-for="item in items" :key="item.id">
{{ item.text }}
</view>
示例 详情
组合式 API
选项式 API
<template>
<!-- #ifdef APP && !VUE3-VAPOR -->
<scroll-view style="flex: 1">
<!-- #endif -->
<view class="page">
<text class="bold mb-10">v-for number</text>
<view class="mb-10" v-for="item in 3" :key="item">
<text :id="`number-${item}`">{{ item }}</text>
</view>
<view class="mb-10" v-for="item in utsNumber" :key="item">
<text :id="`uts-number-${item}`">{{ item }}</text>
</view>
<view class="bold mb-10">v-for object</view>
<view
v-for="(value, key) in object"
:key="key"
class="mb-10 flex justify-between flex-row">
<text :id="key">{{ key }}</text>
<text :id="value">{{ value }}</text>
</view>
<view class="bold mb-10">v-for & v-if list items</view>
<view
id="v-for-v-if-list-items"
v-for="item in listItems"
:key="item.name">
<template v-if="item.show">
<view class="mb-10 flex justify-between flex-row">
<text :id="item.name">{{ item.name }}</text>
<text @click="item.count++" :id="`v-if-${item.name}-count`">{{
item.count
}}</text>
</view>
<template v-for="child in item.items">
<view
v-if="child.show"
:key="child.name"
class="mb-10 flex justify-between flex-row">
<text :id="child.name">{{ child.name }}</text>
<text @click="child.count++" :id="`v-if-${child.name}-count`">{{
child.count
}}</text>
</view>
</template>
</template>
</view>
<view class="bold mb-10">v-for & v-show list items</view>
<view
id="v-for-v-if-list-items"
v-for="item in listItems"
:key="item.name"
v-show="item.show">
<view class="mb-10 flex justify-between flex-row">
<text :id="item.name">{{ item.name }}</text>
<text @click="item.count++" :id="`v-show-${item.name}-count`">{{
item.count
}}</text>
</view>
<view
v-for="child in item.items"
v-show="child.show"
:key="child.name"
class="mb-10 flex justify-between flex-row">
<text :id="child.name">{{ child.name }}</text>
<text @click="child.count++" :id="`v-show-${child.name}-count`">{{
child.count
}}</text>
</view>
</view>
<view
class="mb-10 flex justify-between flex-row"
v-for="item in mapList"
:key="item[0]">
<text>{{ item[0] }}</text>
<text :id="item[0]">{{ item[1] }}</text>
</view>
<view class="mb-10" v-for="(item, index) in setList" :key="index">
<text :id="`set-value-${index + 1}`">{{ item }}</text>
</view>
<view class="bold mb-10">v-for UTSJSONObject</view>
<view
v-for="(value, key) in utsJSONObject"
:key="key"
class="mb-10 flex justify-between flex-row">
<text :id="key">{{ key }}</text>
<text :id="value">{{ value }}</text>
</view>
</view>
<!-- #ifdef APP && !VUE3-VAPOR -->
</scroll-view>
<!-- #endif -->
</template>
<script setup lang="uts">
type VForObject = {
key1 : string
key2 : string
key3 : string
}
type ListItem = {
name: string
count : number
show: boolean
items?: ListItem[]
}
// 可通过泛型指定类型
const object = reactive<VForObject>({ key1: 'value1', key2: 'value2', key3: 'value3' })
const listItems = ref<ListItem[]>([
{ name: '1',
count: 0,
show: true,
items:[
{ name: '1-1', count: 0, show: false },
{ name: '1-2', count: 0, show: true },
]
},
{ name: '2',
count: 0,
show: true,
items:[
{ name: '2-1', count: 0, show: true },
{ name: '2-2', count: 0, show: false },
]
},
{ name: '3',
count: 0,
show: false,
items:[
{ name: '3-1', count: 0, show: true },
{ name: '3-2', count: 0, show: true },
]
},
])
const mapList = new Map<string, string>([
['map-key-1', 'map value 1'],
['map-key-2', 'map value 2'],
['map-key-3', 'map value 3'],
])
const setList = new Set<string>(['set value 1', 'set value 2', 'set value 3'])
const utsJSONObject = reactive({ utsKey1: 'UTSJSONObject-value1', utsKey2: 'UTSJSONObject-value2', utsKey3: 'UTSJSONObject-value3' })
const utsNumber = JSON.parse("3") as number
</script>
给元素绑定事件监听器。
缩写:@
期望的绑定值类型:Function | Object (不带参数)
参数:event (使用对象语法则为可选项)
修饰符
.stop - 调用 event.stopPropagation().once - 最多触发一次处理函数。详见事件修饰符。
示例 详情
组合式 API
选项式 API
<template>
<view class="page">
<text class="bold mb-10">下方按钮点击累加 count</text>
<view class="flex justify-between flex-row mb-10">
<text>count:</text>
<text id="count">{{ count }}</text>
</view>
<button class="mb-10 btn" @click="handleClick">
@click="handleClick" 缩写
</button>
<button class="mb-10 btn" v-on:click="handleClick">
v-on:click="handleClick" 方法处理函数
</button>
<button class="mb-10 btn" v-on:click="count++">
v-on:click="count++" 内联事件
</button>
<button class="mb-10 btn" v-on:click="handleClick($event as MouseEvent)">
v-on:click="handleClick($event as MouseEvent)"
内联声明,注意要显式声明$event的类型
</button>
<!-- #ifndef MP -->
<button class="mb-10 btn" v-on:[event]="handleClick">
v-on:[event]="handleClick" 动态事件
</button>
<button class="mb-10 btn" v-on="{ click: handleClick }">
v-on="{ click: handleClick }" 对象语法
</button>
<!-- #endif -->
<!-- TODO: ios 不支持 -->
<!-- #ifndef APP-IOS || MP || APP-HARMONY -->
<button class="mb-10 btn" id="btn-once" @click.once="handleClick">@click once</button>
<!-- #endif -->
<view @click="handleClick">
<button class="mb-10 btn" id="btn-stop" @click.stop="handleClick">@click stop</button>
</view>
<button class="mb-10" id="btn-prevent" @touchstart.prevent="handleTouchstart" @click="handleClick">@touch prevent</button>
</view>
</template>
<script setup lang="uts">
const count = ref(0)
const event = ref('click')
type BtnPreventRect = {
value: DOMRect | null
}
let btnPreventRect = reactive({
value: null
} as BtnPreventRect)
// #ifdef APP
onReady(() => {
const btnPrevent = uni.getElementById("btn-prevent")
btnPreventRect.value = btnPrevent!.getBoundingClientRect()
btnPreventRect.value!.y += uni.getSystemInfoSync().safeArea.top + 44
})
// #endif
const handleTouchstart = () => {
console.log('handleTouchstart')
}
const handleClick = (e : MouseEvent) => {
count.value++
console.log('handleClick', e)
}
defineExpose({
btnPreventRect
})
</script>
动态的绑定一个或多个 attribute,也可以是组件的 prop。
缩写:
: 或者 . (当使用 .prop 修饰符)期望:any (带参数) | Object (不带参数)
参数:attrOrProp (可选的)
用途
当用于绑定 class 或 style attribute,v-bind 支持额外的值类型如数组或对象。
当用于组件 props 绑定时,所绑定的 props 必须在子组件中已被正确声明。
当不带参数使用时,可以用于绑定一个包含了多个 attribute 名称-绑定值对的对象。
示例 详情
组合式 API
选项式 API
<template>
<!-- #ifdef APP && !VUE3-VAPOR -->
<scroll-view style="flex: 1">
<!-- #endif -->
<view class="page">
<!-- v-bind attribute -->
<button id="disabled-btn" class="mb-10" :disabled="true">
:disabled true
</button>
<button id="v-bind-disabled-btn" class="mb-10" v-bind:disabled="false">
v-bind:disabled false
</button>
<!-- v-bind style -->
<view class="flex justify-between flex-row mb-10">
<text>bind object style fontSize:</text>
<text id="bind-object-style" :style="{ fontSize: dataInfo.fontSize }">
{{ dataInfo.fontSize }}
</text>
</view>
<view id="bind-array-style" class="mb-10 p-10" :style="[dataInfo.backgroundColor, dataInfo.border]">
<view>bind arr style</view>
<view class="my-10">{{ dataInfo.backgroundColor }}</view>
<view>{{ dataInfo.border }}</view>
</view>
<view class="mb-10 p-10">
<text id="bind-raw-object-style" :style="rawObjectStyle">rawObjectStyle</text>
</view>
<!-- 目前仅android平台在内部重新调用了normalizeStyle,其他端暂时没有,这应该是vue的bug -->
<view class="mb-10 p-10">
<text id="bind-raw-array-style" :style="rawArrayStyle">rawArrayStyle</text>
</view>
<!-- v-bind props -->
<Foo class="foo-props" :title="dataInfo.fooProps.title" :num="dataInfo.fooProps.num" :obj="dataInfo.fooProps.obj" />
<!-- v-bind props -->
<Foo checked />
<!-- #ifndef MP -->
<!-- 绑定对象 -->
<Foo id="bindObj1" v-bind="{ title: dataInfo.fooProps.title,num: dataInfo.fooProps.num,obj: dataInfo.fooProps.obj }" />
<!-- 绑定对象合并-->
<Foo id="bindObj2" v-bind="{ title: dataInfo.fooProps.title,num: dataInfo.fooProps.num,obj: dataInfo.fooProps.obj }" title="foo title override" />
<!-- 绑定对象合并-->
<Foo id="bindObj3" title="foo" v-bind="{ title: dataInfo.fooProps.title,num: dataInfo.fooProps.num,obj: dataInfo.fooProps.obj }" />
<!-- 绑定对象合并(UTSJSONObject)-->
<Foo id="bindObj4" v-bind="fooProps" title="foo title(json) override" />
<!-- 绑定对象合并(UTSJSONObject)-->
<Foo id="bindObj5" title="foo" v-bind="fooProps" />
<!-- #endif -->
<!-- v-bind in style -->
<!-- #ifdef WEB -->
<view class="mb-10 v-bind-css"></view>
<!-- #endif -->
</view>
<!-- #ifdef APP && !VUE3-VAPOR -->
</scroll-view>
<!-- #endif -->
</template>
<script setup lang="uts">
import Foo from './Foo-composition.uvue'
import { FooProps, FooPropsObj } from './type.uts'
type DataInfo = {
fontSize : string
backgroundColor : string
border : string
fooProps : FooProps
vBindClassBackgroundColor : string,
vBindClassRpxHeight : string,
}
const dataInfo = reactive({
fontSize: '20px',
backgroundColor: 'background-color: green',
border: 'border: 2px solid red',
fooProps: {
title: 'foo title',
num: 1,
obj: {
name: 'foo obj name',
} as FooPropsObj
},
vBindClassBackgroundColor: 'red',
vBindClassRpxHeight: '300rpx'
} as DataInfo)
const fooProps = reactive({
title: 'foo title(json)',
num: 2,
})
const rawObjectStyle = {
width: '100%',
height: '30px',
'background-color': 'red'
}
const rawArrayStyle = [
{
width: '100%',
height: '30px'
},
{
'background-color': 'red'
}
]
defineExpose({
dataInfo
})
</script>
<style>
/* #ifdef WEB */
.v-bind-css {
background-color: v-bind(dataInfo.vBindClassBackgroundColor);
height: v-bind(dataInfo.vBindClassRpxHeight);
}
/* #endif */
</style>
在表单输入元素或组件上创建双向绑定。
期望的绑定值类型:根据表单输入元素或组件输出的值而变化
仅限:
<input><textarea>修饰符 仅 Android
.lazy - 监听 change 事件而不是 input 事件.number - 将输入的合法字符串转为数字.trim - 移除输入内容两端空格示例 详情
组合式 API
选项式 API
<template>
<view class="page">
<Foo
v-model="str"
v-model:msg="msg"
v-model:strArr="strArr"
v-model:numArr="numArr"
v-model:utsObjModelValue="utsObj['modelValue']"
v-model:typeObjModelValue="typeObj.modelValue"
@update:modelValue="handleModelValueUpdate"
@update:msg="handleModelMsgUpdate"
/>
<input class="mb-10 input" id="model-value-input" v-model="str" @input="onInput" />
<input class="mb-10 input" id="model-msg-input" v-model="msg" />
<input class="mb-10 input" id="model-uts-obj-value-input" v-model="utsObj['modelValue']" />
<input class="mb-10 input" id="model-type-obj-value-input" v-model="typeObj.modelValue" />
<view class="mb-10 flex justify-between flex-row">
<text>handle modelValue update res:</text>
<text id="handle-model-value-update-res">{{ handleModelValueUpdateRes }}</text>
</view>
<view class="mb-10 flex justify-between flex-row">
<text>handle model msg update res:</text>
<text id="handle-model-msg-update-res">{{ handleModelMsgUpdateRes }}</text>
</view>
<Parent v-model="value"></Parent>
<view class="mb-10 flex justify-between flex-row">
<text>arrayValue:</text>
<text id="array-value">{{ arrayValue.region }}</text>
</view>
<ArrayModelChild v-model="arrayValue.region"></ArrayModelChild>
</view>
</template>
<script setup lang="uts">
import Foo from './Foo-composition.uvue'
import Parent from './Parent.uvue'
import ArrayModelChild from './ArrayModelChild.uvue'
import { VModelObj } from './types.uts'
const str = ref('str')
const msg = ref('msg')
const strArr = ref<string[]>(['0'])
const numArr = ref<number[]>([0])
const value = ref("nested");
const arrayValue = reactive({
region: [] as string[]
});
const handleModelValueUpdateRes = ref('')
const handleModelValueUpdate = (val : string) => {
handleModelValueUpdateRes.value = val
}
const handleModelMsgUpdateRes = ref('')
const handleModelMsgUpdate = (val : string) => {
handleModelMsgUpdateRes.value = val
}
const utsObj = reactive({ modelValue: 'utsObj.value' })
const typeObj = reactive({ modelValue: 'typeObj.value' } as VModelObj)
function onInput(){
// noop
}
</script>
<style>
.input {
padding: 0px 10px;
height: 40px;
border: 1px solid #ccc;
border-radius: 4px;
}
</style>
跳过该元素及其所有子元素的编译。
无需传入
详细信息
元素内具有 v-pre,所有 Vue 模板语法都会被保留并按原样渲染。最常见的用例就是显示原始双大括号标签及内容。
示例 详情
<template>
<view class="page">
<text class="bold mb-10">v-pre 跳过该元素及其所有子元素的编译</text>
<text class="mb-10 v-pre-text" v-pre>{{ this will not be compiled }}</text>
</view>
</template>
仅渲染元素和组件一次,并跳过之后的更新。
无需传入
详细信息
在随后的重新渲染,元素/组件及其所有子项将被当作静态内容并跳过渲染。这可以用来优化更新时的性能。
示例 详情
组合式 API
选项式 API
<template>
<view class="page">
<!-- #ifndef MP -->
<view class="flex flex-row justify-between mb-10" v-once>
<text>This msg will never change:</text>
<text id='v-once-msg'>{{ msg }}</text>
</view>
<!-- #endif -->
<view class="flex flex-row justify-between mb-10">
<text>msg:</text>
<text id="msg">{{ msg }}</text>
</view>
<button id="btn" class="mb-10" type="primary" @click="changeMessage">
change message
</button>
</view>
</template>
<script setup lang="uts">
const msg = ref('hello world')
const changeMessage = () => {
msg.value = 'msg changed'
}
</script>
用于声明具名插槽或是期望接收 props 的作用域插槽。
缩写:#
期望的绑定值类型:能够合法在函数参数位置使用的 JavaScript 表达式。支持解构语法。绑定值是可选的——只有在给作用域插槽传递 props 才需要。
参数:插槽名 (可选,默认是 default)
仅限:
<template>示例 详情
组合式 API
选项式 API
<template>
<view class="page">
<Foo>
<template #header="{ msg }">
<view class="mb-10 flex justify-between flex-row">
<text>header slot msg:</text>
<text id="slot-header">{{ msg }}</text>
</view>
</template>
<template #default="{ num }">
<view class="mb-10 flex justify-between flex-row">
<text>default slot num:</text>
<text id="slot-default">{{ num }}</text>
</view>
</template>
<!-- #ifndef MP -->
<template v-for="item in 2" #[`num${item}`]="{ num }">
<view class="mb-10 flex justify-between flex-row">
<text>num{{ item }} slot:</text>
<text :id="`slot-num${item}`">{{ num }}</text>
</view>
</template>
<template v-if="msgTrue['isShow']" #[msgTrue['name']]="{ msg }">
<view class="mb-10 flex justify-between flex-row">
<text>{{ msgTrue['name'] }} slot msg:</text>
<text id="slot-msg-true">{{ msg }}</text>
</view>
</template>
<template v-if="msgFalse['isShow']" #[msgFalse['name']]="{ msg }">
<view class="mb-10 flex justify-between flex-row">
<text>{{ msgFalse['name'] }} slot msg:</text>
<text id="slot-msg-false">{{ msg }}</text>
</view>
</template>
<!-- #endif -->
<template #footer="{ arr }">
<view class="mb-10 flex justify-between flex-row">
<text>footer slot arr:</text>
<text id="slot-footer">{{ JSON.stringify(arr) }}</text>
</view>
</template>
<template #withFor="{ item }">
<view class="mb-10 flex justify-between flex-row">
<text>v-for slot item:</text>
<text :id="`slot-for-${item}`">{{ item }}</text>
</view>
</template>
</Foo>
</view>
</template>
<script setup lang="uts">
import Foo from './Foo-composition.uvue'
const msgTrue = ref({
isShow: true,
name: 'msgTrue'
})
const msgFalse = ref({
isShow: false,
name: 'msgFalse'
})
</script>
期望的绑定值类型:any[]
详细信息
缓存一个模板的子树。在元素和组件上都可以使用。为了实现缓存,该指令需要传入一个固定长度的依赖值数组进行比较。如果数组里的每个值都与最后一次的渲染相同,那么整个子树的更新将被跳过。举例来说:
<view v-memo="[valueA, valueB]">
...
</view>
当组件重新渲染,如果 valueA 和 valueB 都保持不变,这个 <view> 及其子项的所有更新都将被跳过。实际上,甚至虚拟 DOM 的 vnode 创建也将被跳过,因为缓存的子树副本可以被重新使用。
正确指定缓存数组很重要,否则应该生效的更新可能被跳过。v-memo 传入空依赖数组 (v-memo="[]") 将与 v-once 效果相同。
v-memo 仅用于性能至上场景中的微小优化,应该很少需要。最常见的情况可能是有助于渲染海量 v-for 列表 (长度超过 1000 的情况):
当组件的 selected 状态改变,默认会重新创建大量的 vnode,尽管绝大部分都跟之前是一模一样的。v-memo 用在这里本质上是在说“只有当该项的被选中状态改变时才需要更新”。这使得每个选中状态没有变的项能完全重用之前的 vnode 并跳过差异比较。注意这里 memo 依赖数组中并不需要包含 item.id,因为 Vue 也会根据 item 的 :key 进行判断。
警告
当搭配 v-for 使用 v-memo,确保两者都绑定在同一个元素上。v-memo 不能用在 v-for 内部。
v-memo 也能被用于在一些默认优化失败的边际情况下,手动避免子组件出现不需要的更新。但是一样的,开发者需要负责指定正确的依赖数组以免跳过必要的更新。
示例 详情
组合式 API
选项式 API
<template>
<view class="page">
<view class="flex flex-row justify-between mb-10" v-memo="[]">
<text>msg will never change:</text>
<text id="v-memo-never-change-msg">{{ msg }}</text>
</view>
<view class="flex flex-row justify-between mb-10">
<text>msg:</text>
<text id="msg">{{ msg }}</text>
</view>
<view class="flex flex-row justify-between mb-10" v-memo="[num]">
<text>msg will change when num chang:</text>
<text id="v-memo-num-change-msg">{{ msg }}</text>
</view>
<view class="flex flex-row justify-between mb-10">
<text>num:</text>
<text id="num">{{ num }}</text>
</view>
<button
id="change-message-btn"
class="mb-10"
type="primary"
@click="changeMessage">
change message
</button>
<button
id="increment-num-btn"
class="mb-10"
type="primary"
@click="incrementNum">
increment num
</button>
</view>
</template>
<script setup lang="uts">
const msg = ref('hello world')
const num = ref(0)
const changeMessage = () => {
msg.value = 'msg changed'
}
const incrementNum = () =>{
num.value++
}
</script>
注意
scroll-view 标签。组件类型:string
<keep-alive> 包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。和 <transition> 相似,<keep-alive> 是一个抽象组件:它自身不会渲染一个 DOM 元素,也不会出现在父组件链中。
| Web | 微信小程序 | Android(VDOM) | Android(Vapor) | iOS(VDOM) | iOS(Vapor) | HarmonyOS(VDOM) | HarmonyOS(Vapor) |
|---|---|---|---|---|---|---|---|
| 4.0 | x | 4.0 | x | 4.11 | x | 4.61 | x |
| 名称 | 类型 | 兼容性 | 描述 |
|---|---|---|---|
| include | string | 字符串或正则表达式。只有名称匹配的组件会被缓存。 | |
| exclude | string | 字符串或正则表达式。任何名称匹配的组件都不会被缓存。 | |
| max | string | 最多可以缓存多少组件实例。 |
示例 详情
组合式 API
选项式 API
<template>
<!-- #ifdef APP && !VUE3-VAPOR -->
<scroll-view style="flex: 1">
<!-- #endif -->
<view class="page">
<text class="bold mb-10">include="Counter,Message"</text>
<KeepAlive include="Counter,Message">
<component :is="currentComponent"></component>
</KeepAlive>
<view class="hr"></view>
<text class="bold mt-10 mb-10">:include="/Counter|Message/"</text>
<KeepAlive :include="/Counter|Message/">
<component :is="currentComponent"></component>
</KeepAlive>
<view class="hr"></view>
<text class="bold mb-10 mb-10">:include="['Counter', 'Message']"</text>
<KeepAlive :include="['Counter', 'Message']">
<component :is="currentComponent"></component>
</KeepAlive>
<view class="hr"></view>
<text class="bold mt-10 mb-10">exclude="ShouldExclude"</text>
<KeepAlive exclude="ShouldExclude">
<component :is="currentComponent"></component>
</KeepAlive>
<view class="hr"></view>
<text class="bold mt-10 mb-10">:max="2"</text>
<KeepAlive :max="2">
<component :is="currentComponent"></component>
</KeepAlive>
<view class="hr"></view>
<button class="mt-10 show-counter" @click="changeComponent('Counter')">show Counter</button>
<button class="mt-10 show-message" @click="changeComponent('Message')">show Message</button>
<button class="mt-10 show-should-exclude" @click="changeComponent('ShouldExclude')">show ShouldExclude</button>
</view>
<!-- #ifdef APP && !VUE3-VAPOR -->
</scroll-view>
<!-- #endif -->
</template>
<script setup lang="uts">
import Counter from '@/components/keep-alive/Counter.uvue'
import Message from '@/components/keep-alive/Message.uvue'
import ShouldExclude from '@/components/keep-alive/ShouldExclude.uvue'
defineOptions({
components: {
Counter,
Message,
ShouldExclude
}
})
const currentComponent = ref<string>('ShouldExclude')
const changeComponent = (componentName: string) => {
currentComponent.value = componentName
}
</script>
<style>
.hr {
margin: 30rpx 0;
border-bottom: 1px solid #ccc;
}
</style>
组件类型:string
<transition> 元素作为单个元素/组件的过渡效果。<transition> 只会把过渡效果应用到其包裹的内容上,而不会额外渲染 DOM 元素,也不会出现在检测过的组件层级中。
| Web | 微信小程序 | Android | iOS | HarmonyOS |
|---|---|---|---|---|
| 4.0 | x | x | x | x |
| 名称 | 类型 | 兼容性 | 描述 | |||
|---|---|---|---|---|---|---|
| name | string | 用于自动生成 CSS 过渡类名。例如:name: 'fade' 将自动拓展为.fade-enter,.fade-enter-active等。默认类名为 "v" | ||||
| appear | boolean | 是否在初始渲染时使用过渡。默认为 false。 | ||||
| css | boolean | 是否使用 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 属性配置哪个元素应该被渲染。
| Web | 微信小程序 | Android | iOS | HarmonyOS |
|---|---|---|---|---|
| 4.0 | x | x | x | x |
| 名称 | 类型 | 兼容性 | 描述 | |||
|---|---|---|---|---|---|---|
| tag | string | 默认为 span。 | ||||
| move-class | string | 覆盖移动过渡期间应用的 CSS 类。 | ||||
| name | string | 用于自动生成 CSS 过渡类名。例如:name: 'fade' 将自动拓展为.fade-enter,.fade-enter-active等。默认类名为 "v" | ||||
| appear | boolean | 是否在初始渲染时使用过渡。默认为 false。 | ||||
| css | boolean | 是否使用 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,而不必求助于全局状态或将其拆分为两个组件。
| Web | 微信小程序 | Android(VDOM) | Android(Vapor) | iOS(VDOM) | iOS(Vapor) | HarmonyOS(VDOM) | HarmonyOS(Vapor) |
|---|---|---|---|---|---|---|---|
| 4.0 | 5.14 | 4.0 | 5.25 | 4.11 | 5.25 | 4.61 | 5.25 |
| 名称 | 类型 | 兼容性 | 描述 |
|---|---|---|---|
| to | string | 必须是有效的查询选择器或 HTMLElement (如果在浏览器环境中使用)。指定将在其中移动 <teleport> 内容的目标元素 | |
| disabled | boolean | 此可选属性可用于禁用 <teleport> 的功能,这意味着其插槽内容将不会移动到任何位置,而是在您在周围父组件中指定了 <teleport> 的位置渲染。 |
VDOM模式注意事项
to 属性。to 设置为 body。示例 详情
组合式 API
选项式 API
<template>
<!-- #ifdef APP && !VUE3-VAPOR -->
<scroll-view style="flex: 1">
<!-- #endif -->
<view id="container" class="container">
<text class="text">.container 区域</text>
<view id="content1" class="content content-1">
<text class="text">content1 区域</text>
</view>
<view id="content2" class="content content-2">
<text class="text">content2 区域</text>
</view>
<teleport v-if="show" to="#content1" :disabled="disabled">
<view class="send-content">
<text class="send-content-text">内容在.container中,使用teleport在#content1元素中展示</text>
</view>
</teleport>
</view>
<!-- #ifdef APP && !VUE3-VAPOR -->
</scroll-view>
<!-- #endif -->
</template>
<script setup lang="uts">
const to = ref<string>('content1')
const showingString = ref<string>('穿梭内容在 body 中')
const disabled = ref<boolean>(false)
const show = ref<boolean>(false)
onReady(() => {
// 需要等内容挂载后,teleport才生效
show.value = true
})
const changePosition = () => {
to.value = '#content1'
}
defineExpose({
changePosition
})
</script>
<style>
.container {
background-color: #f5f5f5;
border: 1px #ccc solid;
margin: 5px;
padding: 10px;
}
.text {
margin: 5px 0;
}
.content {
height: 120px;
border: 1px #ccc solid;
margin: 5px;
padding: 10px;
}
.send-content {
padding: 5px;
background-color: #ff5a5f;
height: 50px;
}
.send-content-text {
color: #fff;
font-size: 12px;
}
</style>
组件类型:string
当我们想要使用内置指令而不在 DOM 中渲染元素时,<template> 标签可以作为占位符使用。
| Web | 微信小程序 | Android | iOS | HarmonyOS |
|---|---|---|---|---|
| 4.0 | √ | 3.9 | 4.11 | 4.61 |
<template> 有2个用途:
作为单文件组件规范的模板根节点。在 <template> 下面放置页面模板真正的组件内容。
此时lang属性生效。但vue指令不生效。
在根 <template> 下面,继续放置<template>虚节点,可以让多个组件遵守相同的vue指令。
比如下面的示例中,通过<template v-if="isShow">包裹了text和button,让2个组件共同遵守同一个v-if指令,且不增加层级。
如果把这个子<template>改成<view>,会增加一层节点,层级太多会影响性能。
<template>
<view>
<template v-if="isShow">
<text>abc</text>
<button>按钮</button>
</template>
<view></view>
</view>
</template>
此时lang属性不生效。
注意
对非根的 <template> 的特殊处理,只有在它与以下任一指令一起使用时才会被触发:
v-if、v-else-if 或 v-elsev-forv-slot正常情况下,应该搭配如上vue指令使用。但异常情况下,如果这些指令都不存在,那么容错策略如下:
在 Web 端将被渲染成一个原生的 <template> 元素;
在 App 端将被渲染成 view。此时会多个层级。
| 名称 | 类型 | 兼容性 | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
| lang | string | ||||||||||
| |||||||||||
示例 详情
组合式 API
选项式 API
<template>
<view class="page">
<template v-if="dataInfo.isShow">
<text id="title">{{ title }}</text>
</template>
<template v-else>
<text>隐藏标题时显示</text>
</template>
<!-- vapor button 调整实现,自动化测试无法通过 innerText 获取文本内容,重构为 text -->
<text class="mt-10 btn" id="show-botton" @click="handleShow">{{ dataInfo.isShow ? '点击隐藏' : '点击显示' }}</text>
<template v-for="(item, index) in list" :key="index">
<text :class="'item'">{{ index + 1 }}.{{ item.name }}</text>
</template>
<button @click="goMapStyle">跳转绑定 Map 类型 style 页面</button>
</view>
</template>
<script setup lang="uts">
type DataInfo = {
isShow: boolean
}
type ListItem = {
name: string
}
const dataInfo = reactive({
isShow: false
} as DataInfo)
const title = ref<string>('hello')
const list = ref<ListItem[]>([
{
name: 'foo1'
},
{
name: 'foo2'
}
])
const handleShow = () => {
dataInfo.isShow = !dataInfo.isShow
}
const goMapStyle = () => {
uni.navigateTo({ url: '/pages/built-in/special-elements/template/template-map-style-composition' })
}
defineExpose({
dataInfo,
goMapStyle
})
</script>
<style>
.btn{
border: 1px solid #eee;
border-radius: 4px;
text-align: center;
padding-top: 8px;
padding-bottom: 8px;
}
.item {
margin: 15px;
padding: 4px 8px;
border: #eee solid 1px;
}
</style>
组件类型:string
<slot> 元素作为组件模板之中的内容分发插槽。<slot> 元素自身将被替换。
| Web | 微信小程序 | Android | iOS | HarmonyOS |
|---|---|---|---|---|
| 4.0 | 4.11 | 3.9 | 4.11 | 4.61 |
| 名称 | 类型 | 兼容性 | 描述 |
|---|---|---|---|
| name | string | 用于命名插槽。 |
示例 详情
组合式 API
选项式 API
<template>
<view class="content">
<child>
<template v-slot:header="slotProps">
<view class="header">{{ slotProps.msg }}</view>
</template>
<template v-slot:default="{ msg }">
<view class="main">{{ msg }}</view>
</template>
<template #footer="{ msg: text }">
<view class="footer">{{ text }}</view>
</template>
</child>
</view>
</template>
<script setup lang="uts">
import child from './child-composition.uvue'
</script>
组件类型:string
渲染一个“元组件”为动态组件。依 is 的值,来决定哪个组件被渲染。
| Web | 微信小程序 | Android | iOS | HarmonyOS |
|---|---|---|---|---|
| 4.0 | x | 3.99 | 4.11 | 4.61 |
| 名称 | 类型 | 兼容性 |
|---|---|---|
| is | Any | |
| inline-template | boolean |
示例 详情
组合式 API
选项式 API
<template>
<view class="container">
<component :is="currentComponentInstance" />
<component :is="myInput" :value="inputValue" id="my-input" />
<button @click="changeCurrentComponent">change current component</button>
</view>
</template>
<script setup lang="uts">
import Foo from '../../../../components/Foo.uvue'
import Bar from '../../../../components/Bar.uvue'
const currentComponentStr = ref('Foo')
const currentComponentInstance = shallowRef(Foo)
const myInput = ref('input')
const inputValue = ref('default value')
const changeCurrentComponent = () => {
if (currentComponentStr.value === 'Foo') {
currentComponentStr.value = 'Bar'
currentComponentInstance.value = Bar
} else {
currentComponentStr.value = 'Foo'
currentComponentInstance.value = Foo
}
}
defineExpose({
changeCurrentComponent
})
</script>
<style>
.item {
display: flex;
flex-direction: row;
margin: 15px;
border: #eee solid 1px;
}
</style>
| Web | 微信小程序 | Android | iOS | HarmonyOS | |
|---|---|---|---|---|---|
| key | 4.0 | √ | 3.9 | 4.11 | 4.61 |
| ref | 4.0 | √ | 3.9 | 4.11 | 4.61 |
| is | 4.0 | √ | 3.99 | 4.11 | 4.61 |
key 这个特殊的 attribute 主要作为 Vue 的虚拟 DOM 算法提示,在比较新旧节点列表时用于识别 vnode。
预期:number | string | symbol
详细信息
在没有 key 的情况下,Vue 将使用一种最小化元素移动的算法,并尽可能地就地更新/复用相同类型的元素。如果传了 key,则将根据 key 的变化顺序来重新排列元素,并且将始终移除/销毁 key 已经不存在的元素。
同一个父元素下的子元素必须具有唯一的 key。重复的 key 将会导致渲染异常。
最常见的用例是与 v-for 结合:
<view>
<text v-for="item in items" :key="item.id">...</text>
</view>
也可以用于强制替换一个元素/组件而不是复用它。当你想这么做时它可能会很有用:
举例来说:
<transition>
<text :key="text">{{ text }}</text>
</transition>
当 text 变化时,<text> 总是会被替换而不是更新,因此 transition 将会被触发。
用于注册模板引用。
预期:string | Function
详细信息
ref 用于注册元素或子组件的引用。
使用选项式 API,引用将被注册在组件的 this.$refs 对象里:
<script lang="uts">
import Foo from '@/components/Foo.uvue'
export default {
components: { Foo },
mounted() {
// #ifdef APP
(this.$refs['input'] as UniInputElement).setAttribute('value', 'input value');
// #endif
// #ifdef WEB
(this.$refs['input'] as UniInputElement).value = 'input value';
// #endif
// 当在 v-for 中使用模板引用时,this.$refs 中对应的值是一个数组
(this.$refs['textItems'] as UniTextElement[]).forEach((item : UniTextElement) => {
item.style.setProperty('color', 'red')
});
// 调用自定义组件方法
(this.$refs['foo'] as ComponentPublicInstance).$callMethod('updateTitle');
// 获取自定义组件响应式数据
console.log((this.$refs['foo'] as ComponentPublicInstance).$data['title']); // new title
}
}
</script>
<template>
<view>
<input ref="input" />
<text v-for="item in 3" ref="textItems" :key="item">{{
item
}}</text>
<Foo ref="foo" />
</view>
</template>
this.$refs 也是非响应式的,因此你不应该尝试在模板中使用它来进行数据绑定。
使用组合式 API,引用将存储在与名字匹配的 ref 里:
<script setup lang="uts">
import Foo from '@/components/Foo.uvue'
// 声明一个 ref 来存放该元素的引用, 必须和模板里的 ref 同名
const input = ref<UniInputElement | null>(null)
// 当在 v-for 中使用模板引用时,对应的 ref 中包含的值是一个数组
const textItems = ref<UniTextElement[] | null>(null)
// 声明一个 ref 来存放自定义组件的引用, 必须和模板里的 ref 同名
const foo = ref<ComponentPublicInstance | null>(null)
onMounted(() => {
// #ifdef APP
input.value!.setAttribute('value', 'input value')
// #endif
// #ifdef WEB
input.value!.value = 'input value'
// #endif
textItems.value!.forEach((item: UniTextElement) => {
item.style.setProperty('color', 'red')
})
// 调用自定义组件方法
foo.value!.$callMethod('updateTitle')
// 获取自定义组件响应式数据
console.log(foo.value!.$data['title']) // new title
})
</script>
<template>
<view>
<input ref="input" />
<text v-for="item in 3" ref="textItems" :key="item">{{
item
}}</text>
<Foo ref="foo" />
</view>
</template>
<!-- components/Foo.uvue -->
<template>
<view>
<text>title: {{title}}</text>
</view>
</template>
<script>
export default {
name:"Foo",
data() {
return {
title: 'default title'
}
},
methods: {
updateTitle(){
this.title = 'new title'
}
}
}
</script>
ref 获取内置组件实例时会获取到对应的 Element,例如上述代码示例中,input 组件获取到的是 UniInputElement, text 组件获取到的是 UniTextElement,可以调用 Element 的方法和属性。ref 获取自定义组件实例时会获取到对应的 vue 组件实例,例如上述代码示例中,Foo 组件获取到的是 ComponentPublicInstance,可以获取自定义组件的属性或调用方法,详情。ref获取到UniElement需要在此UniElement上设置id,此外小程序平台的UniElement使用是受限的,详情参考:UniElement用于绑定动态组件。
string | Component示例 详情
<template>
<view style="flex: 1; padding: 20px;">
<button id="btn" @click="switchItem">切换详情</button>
<text>页面当前 currentId: </text>
<text id="current-id">{{ currentId }}</text>
<!-- 小程序平台不支持 :key,该页面已在页面注册和入口处通过条件编译屏蔽 -->
<view v-if="currentId != ''" style="margin-top: 20px;">
<Child :key="currentId" :id="currentId" />
</view>
</view>
</template>
<script setup lang="uts">
import Child from './child-composition.uvue'
const currentId = ref('a')
function switchItem() {
currentId.value = currentId.value == 'a' ? 'b' : 'a'
}
</script>