简体中文
vue的一大特色,就是可以定义一个响应式变量,通过模板绑定的写法,更方便的实现对dom的更改。
在组合式里,定义响应式变量是ref()
,在选项式里,定义方式是在data里return。
虽然组合式和选项式的定义方式不一样,但在模板里的绑定和使用方式是一样的。
响应式变量被绑定到UI界面后(template和style都可以),
下面分别讲解各种方式的用法。
选用选项式 API 时,会用 data
选项来声明组件的响应式状态。此选项的值应为返回一个对象的函数。Vue 将在创建新组件实例的时候调用此函数,并将函数返回的对象用响应式系统进行包装。此对象的所有顶层属性都会被代理到组件实例 (即方法和生命周期钩子中的 this
) 上。
data需要特殊类型时,通过 as 来转换。
如下示例中,
{{}}
的方式绑定和显示在text组件的内容区中。即右边预览区显示的3行内容,显示了3个响应式变量的初始值。updateData()
,在这个方法里通过this.
来访问响应式变量,给它们重新赋值。然后界面上3行内容会被自动更新为新值。示例 详情
<template>
<view class="page">
<view class="flex justify-between flex-row mb-10">
<text>str: </text>
<text id="str">{{ str }}</text>
</view>
<view class="flex justify-between flex-row mb-10">
<text>num: </text>
<text id="num">{{ num }}</text>
</view>
<view class="flex justify-between flex-row mb-10">
<text>arr: </text>
<text id="arr">{{ arr.join(',') }}</text>
</view>
<view class="flex justify-between flex-row mb-10">
<text>obj.str: </text>
<text id="obj-str">{{ obj.str }}</text>
</view>
<view class="flex justify-between flex-row mb-10">
<text>obj.num: </text>
<text id="obj-num">{{ obj.num }}</text>
</view>
<view class="flex justify-between flex-row mb-10">
<text>obj.arr: </text>
<text id="obj-arr">{{ obj.arr.join(',') }}</text>
</view>
<view ref='htmlRef' id="idRef" class="flex justify-between flex-row mb-10">
<text>data 存储 element不需要被包装</text>
<text id="isSameRefText">{{ refElementIsSame }}</text>
</view>
<button @click="updateData">update data</button>
</view>
</template>
<script lang="uts">
type Obj = {
str : string,
num : number,
arr : number[]
}
export default {
data() {
return {
str: 'default str',
num: 0,
arr: [1, 2, 3],
// 特殊类型需要通过 as 指定类型
obj: {
str: 'default obj.str',
num: 10,
arr: [4, 5, 6]
} as Obj,
refElement: null as UniElement | null,
refElementIsSame: false
}
},
methods: {
refTest() {
const queryElementById1 = uni.getElementById('idRef')
const queryElementById2 = uni.getElementById('idRef')
const htmlRefElement = this.$refs['htmlRef'] as UniElement;
this.refElement = htmlRefElement
if (queryElementById1 === queryElementById2
&& queryElementById1 === htmlRefElement
&& queryElementById1 === this.refElement) {
this.refElementIsSame = true
}
},
updateData() {
this.str = 'new str'
this.num = 1
this.arr = [4, 5, 6]
this.obj.str = 'new obj.str'
this.obj.num = 100
this.obj.arr = [7, 8, 9]
this.refTest()
},
},
}
</script>
data中的响应式变量,如需在script中使用,需通过 this.xx
的方式,比如上述的this.str
。
组合式 API 没有 data 这种选项,而是通过 ref
、reactive
方法来声明组件的响应式状态。
这种定义方式更加灵活和简洁。
建议把 ref
定义都写在开头,否则到处都写也不好找。
使用 ref()
函数来定义一个响应式变量。
需要给 ref
标注类型时,可通过泛型的写法,如:ref<string>()
, 或使用 as
的写法。
当然 uts 有一定的自动推导能力,对于特别简单的布尔值/数字/字符串的字面量,不写泛型或as,也可以自动推导类型。
ref()
接收参数,并将其包裹在一个带有 .value
属性的 ref
对象中返回。这个对象,
.value
属性。.value
(为了方便起见,在模板中使用时,ref 会自动解包,这样模板里的写法和选项式保持了一致)。如下示例中,
{{}}
的方式绑定和显示在text组件的内容区中。即右边预览区显示的3行内容,显示了3个响应式变量的初始值。increment()
,在这个方法里通过.value
属性给响应式变量自增。然后界面上3行内容会被自动更新为新值。
示例 详情<template>
<view class="page">
<view class="flex justify-between flex-row mb-10">
<text>count:</text>
<text id="count">{{ count }}</text>
</view>
<view class="flex justify-between flex-row mb-10">
<text>str:</text>
<text id="str">{{ str }}</text>
</view>
<view class="flex justify-between flex-row mb-10">
<text>bool:</text>
<text id="bool">{{ bool }}</text>
</view>
<view class="flex justify-between flex-row mb-10">
<text>arr:</text>
<text id="arr">{{ JSON.stringify(arr) }}</text>
</view>
<view class="flex justify-between flex-row mb-10">
<text>counter.count:</text>
<text id="counter-count">{{ counter.count }}</text>
</view>
<button class='mb-10' id="change-count-btn" @click="changeCount">change count</button>
<button class='mb-10' id='change-str-btn' @click='changeStr'>change str</button>
<button class='mb-10' id='change-bool-btn' @click='changeBool'>change bool</button>
<button class='mb-10' id='change-arr-btn' @click='changeArr'>change arr</button>
<button class='mb-10' id='change-counter-btn' @click='changeCounter'>change counter</button>
</view>
</template>
<script setup lang="uts">
// 基础数据类型可自动推导类型
const count = ref(0)
const str = ref('default str')
const bool = ref(false)
// 可通过泛型指定类型
const arr = ref<number[]>([1, 2, 3])
type Counter = {
count : number
}
// 可通过泛型指定类型
const counter = ref<Counter>({
count: 0
})
const changeCount = () => {
count.value++
}
const changeStr = () => {
str.value = 'new str'
}
const changeBool = () => {
bool.value = !bool.value
}
const changeArr = () => {
arr.value.push(arr.value.length + 1)
}
const changeCounter = () => {
counter.value.count++
}
</script>
还有另一种声明响应式状态的方式,即使用 reactive() API。与将内部值包装在特殊对象中的 ref 不同,reactive() 将使对象本身具有响应性,还可以使用 readOnly
来禁止修改。
需要注意:reactive() 返回的是一个原始对象的代理(Proxy),它和原始对象是不相等的。
只有代理对象是响应式的,更改原始对象不会触发更新。因此,使用 Vue 的响应式系统的最佳实践是仅使用你声明对象的代理版本。
示例 详情
<template>
<view class="page">
<view class="flex justify-between flex-row mb-10">
<text>data.str:</text>
<text id="data-str">{{ data.str }}</text>
</view>
<view class="flex justify-between flex-row mb-10">
<text>data.num:</text>
<text id="data-num">{{ data.num }}</text>
</view>
<view class="flex justify-between flex-row mb-10">
<text>data.arr:</text>
<text id="data-arr">{{ JSON.stringify(data.arr) }}</text>
</view>
<view class="flex justify-between flex-row mb-10">
<text>readonly data.str:</text>
<text id="readonly-data-str">{{ readonlyData.str }}</text>
</view>
<view class="flex justify-between flex-row mb-10">
<text>readonly data.num:</text>
<text id="readonly-data-num">{{ readonlyData.num }}</text>
</view>
<view class="flex justify-between flex-row mb-10">
<text>readonly data.arr:</text>
<text id="readonly-data-arr">{{ JSON.stringify(readonlyData.arr) }}</text>
</view>
<button id="update-data-btn" class="mb-10" @click="updateData">
update data
</button>
<button id="update-readonly-data-btn" @click="updateReadonlyData">
update readonly data
</button>
</view>
</template>
<script setup lang="uts">
type Data = {
str : string,
num : number,
arr : string[]
}
// 可通过泛型指定类型
const data = reactive<Data>({
str: 'default str',
num: 0,
arr: ['a', 'b', 'c']
})
// 可通过泛型指定类型
const readonlyData = readonly<Data>(data)
const updateData = () => {
data.str = 'new str'
data.num++
data.arr.push('d')
}
const updateReadonlyData = () => {
readonlyData.str = 'new readonly str'
readonlyData.num++
readonlyData.arr.push('e')
}
</script>
使用 <script setup>
的组件是默认关闭的——即通过模板引用或者 $parent
链获取到的组件的公开实例,不会暴露任何在 <script setup>
中声明的绑定。
可以通过 defineExpose
编译器宏来显式指定在 <script setup>
组件中要暴露出去的属性:
在示例中,使用
defineExpose
导出一个方法供自动化测试脚本使用
示例 详情
<template>
<view class="page">
<define-expose-foo ref="fooRef" />
<view class="flex justify-between flex-row mt-10">
<text>str from component Foo: </text>
<text id="foo-str">{{ fooStr }}</text>
</view>
<view class="flex justify-between flex-row mt-10">
<text>num from component Foo: </text>
<text id="foo-num">{{ fooNum }}</text>
</view>
<button class="increment-btn mt-10" @click="increment">
trigger Foo increment
</button>
</view>
</template>
<script setup lang="uts">
const fooRef = ref<DefineExposeFooComponentPublicInstance | null>(null)
const fooStr = ref('')
const fooNum = ref<number>(0)
onMounted(() => {
fooStr.value = fooRef.value!.str
fooNum.value = fooRef.value!.num
})
const increment = () => {
fooRef.value!.increment()
fooNum.value = fooRef.value!.num
}
</script>
当使用 Options API
data
或 Composition API
的 ref
、 reactive
定义了响应式数据后,可以在模板中使用。
{{}}
语法绑定数据。这常见于<text>
组件。比如下述组件的vue指令:
v-bind
或 :
(简写)。它后面跟着组件的属性名称,可以动态修改组件的属性。v-if
、v-else-if
或 v-else
v-for
示例 详情
选项式 API
组合式 API
<template>
<view class="page">
<template v-if="dataInfo.isShow">
<text id="title">{{ title }}</text>
</template>
<template v-else>
<text>隐藏标题时显示</text>
</template>
<button id="show-botton" @click="handleShow">{{ dataInfo.isShow ? '点击隐藏' : '点击显示' }}</button>
<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 lang='uts'>
type DataInfo = {
isShow: boolean
}
type objType = {
name : string
}
export default {
data() {
return {
title: "hello",
dataInfo: {
isShow: false,
} as DataInfo,
list: [{
name: 'foo1'
},
{
name: 'foo2'
}
] as objType[]
}
},
methods: {
handleShow() {
this.dataInfo.isShow = !this.dataInfo.isShow
},
goMapStyle() {
uni.navigateTo({ url: '/pages/built-in/special-elements/template/template-map-style-options' })
}
}
}
</script>
<style>
.item {
margin: 15px;
padding: 4px 8px;
border: #eee solid 1px;
}
</style>
App | Web |
---|---|
x | 4.13+ |
单文件组件的 <style>
标签支持使用 v-bind
CSS 函数将 CSS 的值链接到动态的组件状态
这个语法同样也适用于 <script setup>
,且支持 UTS 表达式 (需要用引号包裹起来)
v-bind
也可在样式中使用,可以很方便的在 uts 中改变样式,如下所示:
示例 详情
选项式 API
组合式 API
<template>
<!-- #ifdef APP -->
<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>
<!-- v-bind props -->
<Foo :title="dataInfo.fooProps.title" :num="dataInfo.fooProps.num" :obj="dataInfo.fooProps.obj" />
<!-- v-bind props -->
<Foo checked />
<!-- 绑定对象 -->
<Foo v-bind="{ title: dataInfo.fooProps.title,num: dataInfo.fooProps.num,obj: dataInfo.fooProps.obj }" />
<Foo v-bind="fooProps"/>
<Foo id="bindObj1" v-bind="{ title: dataInfo.fooProps.title,num: dataInfo.fooProps.num,obj: dataInfo.fooProps.obj }" />
<!-- 绑定对象合并 v-bind 在前 -->
<Foo v-bind="{ title: dataInfo.fooProps.title,num: dataInfo.fooProps.num,obj: dataInfo.fooProps.obj }" id="bindObj2" :title="dataInfo.fooProps.title + ' override'" />
<!-- 绑定对象合并 v-bind 在后 -->
<Foo id="bindObj3" title="foo" v-bind="{ title: dataInfo.fooProps.title,num: dataInfo.fooProps.num,obj: dataInfo.fooProps.obj }" />
<!-- 绑定对象合并 v-bind 在中间(UTSJSONObject)-->
<Foo id="bindObj4" v-bind="fooProps" title="foo title(json) override" />
<!-- 绑定对象合并(UTSJSONObject)-->
<Foo id="bindObj5" title="foo" v-bind="fooProps" />
<!-- v-bind in style -->
<!-- #ifdef WEB -->
<view class="mb-10 v-bind-css"></view>
<!-- #endif -->
</view>
<!-- #ifdef APP -->
</scroll-view>
<!-- #endif -->
</template>
<script lang="uts">
import Foo from './Foo-options.uvue'
import { FooProps, FooPropsObj } from './type.uts'
type DataInfo = {
fontSize : string
backgroundColor : string
border : string
fooProps : FooProps
vBindClassBackgroundColor : string
vBindClassRpxHeight : string
}
export default {
components: { Foo },
data() {
return {
dataInfo: {
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,
fooProps:{
title: 'foo title(json)',
num: 2,
}
}
}
}
</script>
<style>
/* #ifdef WEB */
.v-bind-css {
background-color: v-bind(dataInfo.vBindClassBackgroundColor);
height: v-bind(dataInfo.vBindClassRpxHeight);
}
/* #endif */
</style>
使用选项式 API 时可以在 methods
选项中定义方法,这些方法可以在模板中使用
而使用组合式 API 时,可以直接在 <script setup lang="uts">
中定义方法
定义方法之后,可以传递给子组件,子组件使用 emit
调用,也可以在 script
中直接使用
示例 详情
<template>
<view class="page">
<view class="flex justify-between flex-row mb-10">
<text>count:</text>
<text id="count">{{ count }}</text>
</view>
<view class="flex justify-between flex-row mb-10">
<text>str:</text>
<text id="str">{{ str }}</text>
</view>
<view class="flex justify-between flex-row mb-10">
<text>bool:</text>
<text id="bool">{{ bool }}</text>
</view>
<view class="flex justify-between flex-row mb-10">
<text>arr:</text>
<text id="arr">{{ JSON.stringify(arr) }}</text>
</view>
<view class="flex justify-between flex-row mb-10">
<text>counter.count:</text>
<text id="counter-count">{{ counter.count }}</text>
</view>
<button class='mb-10' id="change-count-btn" @click="changeCount">change count</button>
<button class='mb-10' id='change-str-btn' @click='changeStr'>change str</button>
<button class='mb-10' id='change-bool-btn' @click='changeBool'>change bool</button>
<button class='mb-10' id='change-arr-btn' @click='changeArr'>change arr</button>
<button class='mb-10' id='change-counter-btn' @click='changeCounter'>change counter</button>
</view>
</template>
<script setup lang="uts">
// 基础数据类型可自动推导类型
const count = ref(0)
const str = ref('default str')
const bool = ref(false)
// 可通过泛型指定类型
const arr = ref<number[]>([1, 2, 3])
type Counter = {
count : number
}
// 可通过泛型指定类型
const counter = ref<Counter>({
count: 0
})
const changeCount = () => {
count.value++
}
const changeStr = () => {
str.value = 'new str'
}
const changeBool = () => {
bool.value = !bool.value
}
const changeArr = () => {
arr.value.push(arr.value.length + 1)
}
const changeCounter = () => {
counter.value.count++
}
</script>