Vue3和Vue2的一个比较大的区别是Vue3提供了组合式API,它的说明和优点可以参考官方文档组合式 API FAQ。
在实际项目中,一般都是用Vue的单文件组件开发,而在Vue3中通常就是组合式API + 搭配来开发单文件组件。
而我们之所以喜欢用Vue,主要是馋它的双向绑定,在Vue3中,声明响应式对象主要有reactive和ref这2种方式。
可以用reactive()创建一个响应式对象、数组或Map、Set,不能创建string、number、boolean这样的原始类型。
下面分别给出用reactive创建对象和对象数组的案例。
<template>
<el-button @click="addAge">加1按钮</el-button>
{{ state.age }}
</template>
<script setup lang="ts">
import {reactive} from "vue";
//使用reactive创建一个响应式对象
const state = reactive({
name: '',
age: 0
});
function addAge() {
state.age++;
}
</script>
<template>
<li v-for="item in dataList">
{{ item.name }}
</li>
</template>
<script setup lang="ts">
import { reactive } from "vue";
//定义User接口
interface User {
name: string,
age: number
}
const dataList = reactive<User[]>([
{
name: "Piano1",
age: 1
},
{
name: "Piano2",
age: 2
}
])
</script>
非常重要的一点是,reactive()返回的是原始对象的Proxy(代理)。这个代理和原始对象是不相等的。
const raw = {}
const proxy = reactive(raw)
当修改proxy的值,页面的DOM会更新,但修改原始对象raw,DOM不会更新,raw它不是响应式的。
所以最好的实践是:仅使用响应式的proxy,不要用原始对象。
还有我们不可以随意“替换”一个响应式对象,这会导致对原始引用的响应性连接丢失。
let state = reactive({ count: 0 })
// 上面的引用 ({ count: 0 }) 将不再被追踪(响应性连接已丢失!)
state = reactive({ count: 1 })
ref()和reactive()类似,它不光可以创建响应式的对象,还可以创建string、number、boolean等响应式的原始类型。
<template>
为顶层 property 被访问时,不需要用.value
{{ name }} {{ age }} {{ status }}
</template>
<script setup lang="ts">
import {onMounted, ref} from "vue";
const name = ref('');
const age = ref(1);
const status = ref(false);
//需要用.value来获取ref对象
onMounted(() => {
name.value = "winter";
age.value = 33;
status.value = true;
});
</script>
<template>
<li v-for="item in iconList">
{{ item }}
</li>
{{ user.name }}
{{ user.age }}
<li v-for="item in userList">
{{ item.name }}
</li>
</template>
<script setup lang="ts">
import {onMounted, ref} from "vue";
interface User {
name: string,
age: number
}
//创建string数组
const iconList = ref([] as string[]);
//创建User对象
const user = ref({});
//创建User对象数组
const userList = ref([] as Array<User>);
onMounted(() => {
iconList.value.push('add','edit');
user.value = {
name: "Piano1",
age: 1
};
userList.value = [
{name: "Piano1", age: 1},
{name: "Piano2",age: 2}
];
});
</script>
当我们更新ref或reactive创建的响应式状态后,DOM会自动更新。但是这种更新不是同步的,它有一定延迟,Vue是周期性更新DOM,会把改变缓存起来,等到周期性的“下个时机”去更新DOM。
如果要等待一个状态改变后,DOM也更新完成,我们可以使用nextTick()这个全局API:
viewState.editDialog.visible是指编辑弹框的显示/隐藏的状态,默认是false。
当要希望编辑框真正显示后,再执行initEditData()方法,就要在nextTick()里面调用initEditData()。
function handleEdit(id: string) {
viewState.editDialog.visible = true;
nextTick(() => {
dictTypeEditDialog.value.initEditData(id);
})
}