一、非响应式数据
- 只有在 setup 函数中被 return 暴露的变量才可在模板中使用
- 只能用于初始化渲染视图,不可再次改变视图
<template>
<div>{{ count }}</div>
<!-- 不报错也不生效 -->
<button @click="count++">count add</button>
</template>
<script>
export default {
setup() {
const count = 1;
return { count };
},
};
</script>
二、基础类型响应式数据(基础类型)
- 通过 ref()函数将基础类型数据包装成响应式数据
- 在 setup 函数中使用 ref() 包装的数据的值,需要通过.value 的方式
- 在模板中使用 ref() 包装的数据,直接使用,不使用.value 的方式
<template>
<div>{{ count }}</div>
<button @click="count++">count add 模板</button>
<button @click="handleCountAdd()">count add setup</button>
</template>
<script>
import { ref } from "vue";
export default {
setup() {
const count = ref(1);
console.log(count);
const handleCountAdd = () => {
count.value++;
};
return { count, handleCountAdd };
},
};
</script>
三、对象类型响应式数据(对象和数组)
1. 通过 ref() 定义对象类型响应式数据
- 通过 ref()函数将对象类型数据包装成响应式数据
- 在 setup 函数中使用 ref() 包装的数据的值,需要通过.value 的方式
- 在模板中使用 ref() 包装的数据,直接使用,不使用.value
- ref()函数包装的对象数据是深层次的响应式数据(原理是当给 ref()传入对象时,实际上调用了 reactive()函数)
<template>
<div>教师姓名:{{ teacher.name }}</div>
<div>教师年龄:{{ teacher.age }}</div>
<button @click="handleTeacherChange()">change teacher</button>
</template>
<script>
import { ref } from "vue";
export default {
setup() {
let teacher = ref({});
setTimeout(() => {
teacher.value = {
name: "venus",
age: 30,
};
}, 1000);
const handleTeacherChange = () => {
teacher.value = {
name: "alias",
age: 40,
};
teacher.value.name = "tom";
};
return { teacher, handleTeacherChange };
},
};
</script>
2. 通过 reactive() 定义对象类型响应式数据
- reactive() 只能用于定义对象类型响应式数据,不能定义基础类型响应式数据
<template>
<div>教师姓名:{{ state.teacher.name }}</div>
<div>教师年龄:{{ state.teacher.age }}</div>
<button @click="handleTeacherChange()">change teacher</button>
</template>
<script>
import { reactive } from "vue";
export default {
setup() {
const state = reactive({ teacher: {} });
console.log(state);
setTimeout(() => {
state.teacher = {
name: "venus",
age: 30,
};
}, 1000);
const handleTeacherChange = () => {
state.teacher = {
name: "alias",
age: 40,
};
state.teacher.name = "tom";
};
return { state, handleTeacherChange };
},
};
</script>
- toRefs() 将一个响应式对象转换为一个普通对象,这个普通对象的每个属性都是指向源对象相应属性的 ref
常用于批量解构 reactive()包装的响应式对象,将响应式对象的某些属性暴露给模板使用
<template>
<div>教师姓名:{{ teacher.name }}</div>
<div>教师年龄:{{ teacher.age }}</div>
<button @click="handleTeacherChange()">change teacher</button>
</template>
<script>
import { reactive, toRefs } from "vue";
export default {
setup() {
const state = reactive({ teacher: {} });
console.log(state);
setTimeout(() => {
state.teacher = {
name: "venus",
age: 30,
};
}, 1000);
const handleTeacherChange = () => {
state.teacher = {
name: "alias",
age: 40,
};
state.teacher.name = "tom";
};
return { ...toRefs(state), handleTeacherChange };
},
};
</script>
- toRef() 是基于响应式对象(reactive 或者 ref 包装的对象)上的一个属性,创建一个对应的 ref。这样创建的 ref 与其源属性保持同步
常用于单独解构 reactive()包装的响应式对象,将响应式对象的某个属性暴露给模板使用,
最常用的是 props 参数解构(由于 props 解构后会失去响应式功能,所以需要通过 toRef()解构需要的属性)
<template>
<div>
<div>{{ state.foo }}</div>
<div>{{ fooRef }}</div>
</div>
</template>
<script setup>
import { reactive, toRef } from "vue";
const state = reactive({
foo: 1,
bar: 2,
});
const fooRef = toRef(state, "foo");
// 更改该 ref 会更新源属性
fooRef.value++;
console.log(state.foo); // 2
// 更改源属性也会更新该 ref
state.foo++;
console.log(fooRef.value); // 3
</script>
- vue3 中 ref()、reactive() 包装的响应式数据是深层次的,解决了 vue2 中对象数据删除、增加属性和通过索引改变数组值视图不更新问题
<template>
<div>
<ul>
<li v-for="item in names" :key="item">{{ item }}</li>
</ul>
<button @click="replaceNames">replaceNames</button>
</div>
<hr />
<div>
<div>
<ul>
<li>{{ userinfo.username }}</li>
<li>{{ userinfo.password }}</li>
</ul>
<div><button @click="deleteInfo">deleteInfo</button></div>
<div><button @click="addInfo">addInfo</button></div>
</div>
</div>
</template>
<script setup>
import { ref } from "vue";
const names = ref(["卡罗", "老蔫儿", "贼大胆"]);
function replaceNames() {
names.value[0] = "卡梅利多";
}
const userinfo = ref({ username: "卡梅利多", password: "123456" });
function deleteInfo() {
delete userinfo.value.username;
}
function addInfo() {
userinfo.value.username = "卡梅利多";
}
</script>
四、定义数据的其他方式 --- shallowReactive()、shallowRef()、readonly()、shallowReadonly()、toRaw()、markRaw()
- shallowReactive() 是 reactive() 的浅层作用形式
只有第一层是响应式数据
- shallowRef() 是 ref() 的浅层作用形式
只有对第一次 .value 的访问是响应式的,常常用于对大型数据结构的性能优化或是与外部的状态管理系统集成
- readonly() 创建深层只读数据
每一层都不可修改,常用于后代组件传参时,禁止子组件修改响应式数据(单向数据流)
- shallowReadonly() 是 readonly() 的浅层作用形式
只有第一层不可修改,其他层可修改,且是响应式数据
- toRaw() 传入代理对象返回原始对象
将响应式数据变成原始数据(暂时)
- markRaw() 传入代理对象返回原始对象,不可再次转变为响应式对象
将响应式数据变成原始数据(永久)
五、响应式数据类型的判断 isReactive(), isReadonly(), isRef()
<template>
<h1>App</h1>
<div>{{ refCount }}</div>
<div>{{ ReactiveCount.count }}</div>
<div>{{ readonlyCount }}</div>
</template>
<script setup>
import { isReactive, isReadonly, isRef, reactive, readonly, ref } from 'vue'
const refCount = ref(1)
const ReactiveCount = reactive({
count: 1
})
const readonlyCount = readonly({
count: 1
})
console.log(isRef(refCount)) // true
console.log(isReactive(ReactiveCount)) // true
console.log(isReadonly(readonlyCount)) // true
</script>
网友评论