一平绩、非響應(yīng)式數(shù)據(jù)
- 只有在 setup 函數(shù)中被 return 暴露的變量才可在模板中使用
- 只能用于初始化渲染視圖薛耻,不可再次改變視圖
<template>
<div>{{ count }}</div>
<!-- 不報(bào)錯(cuò)也不生效 -->
<button @click="count++">count add</button>
</template>
<script>
export default {
setup() {
const count = 1;
return { count };
},
};
</script>
二醋闭、基礎(chǔ)類型響應(yīng)式數(shù)據(jù)(基礎(chǔ)類型)
- 通過 ref()函數(shù)將基礎(chǔ)類型數(shù)據(jù)包裝成響應(yīng)式數(shù)據(jù)
- 在 setup 函數(shù)中使用 ref() 包裝的數(shù)據(jù)的值蘸朋,需要通過.value 的方式
- 在模板中使用 ref() 包裝的數(shù)據(jù)谢翎,直接使用算墨,不使用.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>
三蹲嚣、對(duì)象類型響應(yīng)式數(shù)據(jù)(對(duì)象和數(shù)組)
1. 通過 ref() 定義對(duì)象類型響應(yīng)式數(shù)據(jù)
- 通過 ref()函數(shù)將對(duì)象類型數(shù)據(jù)包裝成響應(yīng)式數(shù)據(jù)
- 在 setup 函數(shù)中使用 ref() 包裝的數(shù)據(jù)的值赚瘦,需要通過.value 的方式
- 在模板中使用 ref() 包裝的數(shù)據(jù),直接使用寺谤,不使用.value
- ref()函數(shù)包裝的對(duì)象數(shù)據(jù)是深層次的響應(yīng)式數(shù)據(jù)(原理是當(dāng)給 ref()傳入對(duì)象時(shí)仑鸥,實(shí)際上調(diào)用了 reactive()函數(shù))
<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() 定義對(duì)象類型響應(yīng)式數(shù)據(jù)
- reactive() 只能用于定義對(duì)象類型響應(yīng)式數(shù)據(jù),不能定義基礎(chǔ)類型響應(yīng)式數(shù)據(jù)
<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() 將一個(gè)響應(yīng)式對(duì)象轉(zhuǎn)換為一個(gè)普通對(duì)象变屁,這個(gè)普通對(duì)象的每個(gè)屬性都是指向源對(duì)象相應(yīng)屬性的 ref
常用于批量解構(gòu) reactive()包裝的響應(yīng)式對(duì)象眼俊,將響應(yīng)式對(duì)象的某些屬性暴露給模板使用
<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() 是基于響應(yīng)式對(duì)象(reactive 或者 ref 包裝的對(duì)象)上的一個(gè)屬性,創(chuàng)建一個(gè)對(duì)應(yīng)的 ref粟关。這樣創(chuàng)建的 ref 與其源屬性保持同步
常用于單獨(dú)解構(gòu) reactive()包裝的響應(yīng)式對(duì)象疮胖,將響應(yīng)式對(duì)象的某個(gè)屬性暴露給模板使用,
最常用的是 props 參數(shù)解構(gòu)(由于 props 解構(gòu)后會(huì)失去響應(yīng)式功能,所以需要通過 toRef()解構(gòu)需要的屬性)
<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 會(huì)更新源屬性
fooRef.value++;
console.log(state.foo); // 2
// 更改源屬性也會(huì)更新該 ref
state.foo++;
console.log(fooRef.value); // 3
</script>
- vue3 中 ref()澎灸、reactive() 包裝的響應(yīng)式數(shù)據(jù)是深層次的院塞,解決了 vue2 中對(duì)象數(shù)據(jù)刪除、增加屬性和通過索引改變數(shù)組值視圖不更新問題
<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>
四性昭、定義數(shù)據(jù)的其他方式 --- shallowReactive()拦止、shallowRef()、readonly()巩梢、shallowReadonly()创泄、toRaw()、markRaw()
- shallowReactive() 是 reactive() 的淺層作用形式
只有第一層是響應(yīng)式數(shù)據(jù)
- shallowRef() 是 ref() 的淺層作用形式
只有對(duì)第一次 .value 的訪問是響應(yīng)式的括蝠,常常用于對(duì)大型數(shù)據(jù)結(jié)構(gòu)的性能優(yōu)化或是與外部的狀態(tài)管理系統(tǒng)集成
- readonly() 創(chuàng)建深層只讀數(shù)據(jù)
每一層都不可修改,常用于后代組件傳參時(shí)饭聚,禁止子組件修改響應(yīng)式數(shù)據(jù)(單向數(shù)據(jù)流)
- shallowReadonly() 是 readonly() 的淺層作用形式
只有第一層不可修改忌警,其他層可修改,且是響應(yīng)式數(shù)據(jù)
- toRaw() 傳入代理對(duì)象返回原始對(duì)象
將響應(yīng)式數(shù)據(jù)變成原始數(shù)據(jù)(暫時(shí))
- markRaw() 傳入代理對(duì)象返回原始對(duì)象秒梳,不可再次轉(zhuǎn)變?yōu)轫憫?yīng)式對(duì)象
將響應(yīng)式數(shù)據(jù)變成原始數(shù)據(jù)(永久)
五法绵、響應(yīng)式數(shù)據(jù)類型的判斷 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>