vue3?setup中使用響應(yīng)式的方法
基本類型的響應(yīng)式數(shù)據(jù)
在 Vue 3 中,
ref是一個(gè)函數(shù),用于創(chuàng)建響應(yīng)式的數(shù)據(jù)。它主要用于處理基本類型(如數(shù)字、字符串、布爾值等)的數(shù)據(jù)響應(yīng)式
當(dāng)我們調(diào)用 ref 函數(shù)時(shí),會(huì)返回一個(gè)包含一個(gè) .value 屬性的對(duì)象。這個(gè)對(duì)象會(huì)被轉(zhuǎn)換成 Proxy 對(duì)象,通過(guò)攔截 getter 和 setter 操作,實(shí)現(xiàn)對(duì) .value 屬性的監(jiān)聽(tīng)。當(dāng)讀取 .value 屬性時(shí),會(huì)觸發(fā) getter操作,將 .value 屬性的值返回。當(dāng)修改 .value 屬性時(shí),會(huì)觸發(fā) setter操作,將新的值賦給 .value 屬性
<script setup lang="ts" name="UserInfo">
// 導(dǎo)入ref
import {ref} from "vue"
// 需要讓哪個(gè)數(shù)據(jù)是響應(yīng)式的,就給哪個(gè)數(shù)據(jù)使用ref
let age = ref(18)
let name = ref("vue3")
// 不需要響應(yīng)式
let address:string = "Beijing"
// ref返回的是一個(gè)響應(yīng)式對(duì)象,里面的value是具體的值
// 在template模版中使用 例如age,不需要age.value,模版會(huì)自動(dòng).value解析
// 但是在ts、js代碼中使用,需要.value
function setAge(){
age.value = 20 // 將value改成20,響應(yīng)式修改
}
</script><template>
{{ age }}
{{ name }}
{{address}}
<button @click="setAge">修改年齡</button>
</template>ref也可以用于處理對(duì)象和數(shù)組,但對(duì)于復(fù)雜類型,reactive函數(shù)可能更加合適
<script setup lang="ts" name="UserInfo">
import {ref} from "vue"
// 響應(yīng)式對(duì)象數(shù)據(jù)
// ref處理對(duì)象的原理-底層調(diào)用了reactive
let info = ref({name: "vue3", age: 18})
// 修改age
function setAge() {
info.value.age = 20
}
</script><template>
{{ info.age }}
{{ info.name }}
<button @click="setAge">修改年齡</button>
</template>對(duì)象類型的響應(yīng)式數(shù)據(jù)
reactive是一個(gè)用于創(chuàng)建響應(yīng)式對(duì)象的函數(shù)。它主要用于處理復(fù)雜的數(shù)據(jù)類型,如對(duì)象和數(shù)組,使得這些數(shù)據(jù)成為響應(yīng)式數(shù)據(jù),即當(dāng)數(shù)據(jù)的內(nèi)容發(fā)生變化時(shí),與之綁定的組件模板會(huì)自動(dòng)更新
當(dāng)我們調(diào)用 reactive 函數(shù)時(shí),會(huì)將傳入的普通 JavaScript 對(duì)象轉(zhuǎn)換為一個(gè) Proxy 對(duì)象,通過(guò)攔截 getter 和 setter 操作,實(shí)現(xiàn)對(duì)整個(gè)對(duì)象的監(jiān)聽(tīng)。當(dāng)讀取對(duì)象的屬性時(shí),會(huì)觸發(fā) getter操作,返回對(duì)應(yīng)屬性的值。當(dāng)修改對(duì)象的屬性時(shí),會(huì)觸發(fā) setter操作,將新的值賦給對(duì)應(yīng)的屬性
<script setup lang="ts" name="UserInfo">
// 導(dǎo)入reactive
import {reactive} from "vue"
// 需要讓哪個(gè)對(duì)象是響應(yīng)式的,就給哪個(gè)對(duì)象使用ref
// 響應(yīng)式對(duì)象
let info = reactive({name:"vue3",age:18})
// 非響應(yīng)式對(duì)象
let ext = {address:"Beijing"}
// 修改age
function setAge(){
info.age = 20
}
</script><template>
{{ info.age }}
{{ info.name }}
{{ext.address}}
<button @click="setAge">修改年齡</button>
</template>ref和reactive的區(qū)別
ref可以用來(lái)定義基本數(shù)據(jù)類型、對(duì)象數(shù)據(jù)類型
reactive只能用來(lái)定義對(duì)象數(shù)據(jù)類型
若需要一個(gè)基本類型的響應(yīng)式數(shù)據(jù),必須使用ref
若需要一個(gè)響應(yīng)式對(duì)象,層級(jí)不深,ref、reactive都可以。
若需要一個(gè)響應(yīng)式對(duì)象,且層級(jí)較深,推薦使用reactive
ref創(chuàng)建的變量必須使用.value
reactive重新分配一個(gè)新對(duì)象,會(huì)失去響應(yīng)式,可以使用Object.assign整體替換
let info = reactive({name: "vue3", age: 18}) // info = {name:"vue2"},給info重新分配對(duì)象,會(huì)失去響應(yīng)式 // info = reactive({name:"vue2"}) 不能使用該方式重新分配響應(yīng)式對(duì)象,使用該方式后,不是原先的響應(yīng)式info是一個(gè)新的響應(yīng)式info,頁(yè)面不更新 // 使用這種方式重新分配對(duì)象 Object.assign(info,{name:"vue2",age:20})
如果是使用ref創(chuàng)建的響應(yīng)式對(duì)象,重新分配一個(gè)對(duì)象,可以直接分配
let info = ref({name: "vue3", age: 18})
// 直接賦值替換,也是響應(yīng)式的,通過(guò).value拿到替換,.value拿到的就是響應(yīng)式的
info.value = {name:"3",age:20}
// 響應(yīng)式基本數(shù)據(jù)類型不能直接這樣修改,需要通過(guò).value
// 使用該方式相當(dāng)于創(chuàng)建了一個(gè)新的響應(yīng)式,而不是原先的響應(yīng)式,頁(yè)面是跟原先的響應(yīng)式關(guān)聯(lián)
let count = ref(10)
count = ref(20)toRefs和toRef
- 作用:將一個(gè)響應(yīng)式對(duì)象中的每一個(gè)屬性,轉(zhuǎn)換為
ref對(duì)象。- 備注:
toRefs與toRef功能一致,但toRefs可以批量轉(zhuǎn)換
let info = reactive({name: "vue3", age: 18})
// 解構(gòu)賦值
let {name, age} = info
function setInfo() {
//頁(yè)面沒(méi)有響應(yīng)式變化
// 變化的數(shù)據(jù)是解構(gòu)出來(lái)的age,而不是info.age
age += 1
}// 解構(gòu)賦值
// 底層實(shí)現(xiàn)是將每一個(gè)屬性 使用ref進(jìn)行轉(zhuǎn)換,都是ref對(duì)象
// toRefs可以批量轉(zhuǎn)換
let {name, age} = toRefs(info)
function setInfo() {
// 頁(yè)面數(shù)據(jù)可以響應(yīng)式變化
age.value += 1
}// toRef只能轉(zhuǎn)換單個(gè) let age = toRef(info,age)
計(jì)算屬性
根據(jù)已有數(shù)據(jù)計(jì)算出新數(shù)據(jù)(和Vue2中的computed作用一致)
計(jì)算屬性是有緩存的,多個(gè)場(chǎng)景使用一個(gè)計(jì)算屬性,計(jì)算數(shù)據(jù)不發(fā)生變化,則只計(jì)算一次
- 只讀計(jì)算屬性
// 導(dǎo)入computed計(jì)算屬性,是一個(gè)函數(shù)
import {computed, ref} from "vue"
let name = ref("vue")
let age = ref(20)
// 計(jì)算屬性
// 只讀取的計(jì)算屬性,不能通過(guò)info=xxx這種方式修改info
let info = computed(() => name.value + "-" + age.value)- 可讀可修改計(jì)算屬性
// 導(dǎo)入computed計(jì)算屬性,是一個(gè)函數(shù)
import {computed, ref} from "vue"
let name = ref("vue")
let age = ref(20)
// 計(jì)算屬性
let info = computed({
get() {
return name + "-" + age
},
set(value) {
// value需要是 xx-xxx的數(shù)據(jù)格式
// 將數(shù)據(jù)用-切割
const [str1,str2] = value.split("-")
// 將數(shù)據(jù)賦值給name和age 觸發(fā)重新計(jì)算 然后生成新的info
name.value = str1
age.value = Number(str2)
}
})監(jiān)視屬性
- 作用:監(jiān)視數(shù)據(jù)的變化(和
Vue2中的watch作用一致) - 特點(diǎn):
Vue3中的watch只能監(jiān)視以下四種數(shù)據(jù):
ref定義的數(shù)據(jù)。
reactive定義的數(shù)據(jù)。函數(shù)返回一個(gè)值(
getter函數(shù))一個(gè)包含上述內(nèi)容的數(shù)組
ref基本數(shù)據(jù)類型
直接寫數(shù)據(jù)名監(jiān)視,監(jiān)視的是該數(shù)據(jù)value值的改變
// 導(dǎo)入watch
import {watch, ref} from "vue"
let name = ref("vue")
let age = ref(20)
// 監(jiān)視
// 要監(jiān)視的屬性不需要寫.value,回調(diào)函數(shù)(該屬性新值,該屬性舊值)
const wa = watch(name, (newValue, oldValue) => {
console.log("新數(shù)據(jù)",newValue,"舊數(shù)據(jù)",oldValue)
// 如果新數(shù)據(jù) 的長(zhǎng)度大于等于10的時(shí)候,停止監(jiān)視
if (newValue.length >=10){
// 原理:watch函數(shù)會(huì)返回一個(gè)函數(shù)。這個(gè)返回的函數(shù)實(shí)際上是一個(gè)用于清理或停止監(jiān)視操作的句柄
wa()
}
})ref對(duì)象類型數(shù)據(jù)
監(jiān)視的是對(duì)象的【地址值】,若想監(jiān)視對(duì)象內(nèi)部的數(shù)據(jù),要手動(dòng)開(kāi)啟深度監(jiān)視
// 導(dǎo)入watch
import {watch, ref} from "vue"
let info = ref({name: "vue", category: "js"})
// 監(jiān)視的是對(duì)象的內(nèi)存地址的值
// info.value = {}的時(shí)候會(huì)觸發(fā),修改里面某個(gè)屬性不好觸發(fā)
watch(info, (newValue, oldValue) => {
// 如果修改整個(gè)對(duì)象,newValue是新對(duì)象,oldValue是舊對(duì)象
console.log(newValue, oldValue)
})watch的第三個(gè)參數(shù)是一個(gè)配置對(duì)象,deep、immediate等等
watch(info, (newValue, oldValue) => {
// 如果修改某個(gè)屬性,newValue, oldValue兩個(gè)都是新值,因?yàn)樗麄兪峭粋€(gè)對(duì)象
// 如果修改整個(gè)對(duì)象才會(huì)是兩個(gè)對(duì)象
console.log(newValue, oldValue)
// deep開(kāi)啟深度監(jiān)視,修改里面的某個(gè)屬性 、修改整個(gè)對(duì)象 都會(huì)觸發(fā)
// immediate在watch函數(shù)創(chuàng)建的時(shí)候立即執(zhí)行一次回調(diào)函數(shù)
},{deep:true,immediate:true})reactive對(duì)象數(shù)據(jù)類型
監(jiān)視r(shí)eactive對(duì)象,默認(rèn)開(kāi)啟了深度監(jiān)視
import {watch, ref, reactive} from "vue"
let info = reactive({name: "vue", category: "js"})
watch(info, (newValue, oldValue) => {
// newValue, oldValue不管是修改整個(gè)對(duì)象還是某個(gè)屬性,都是新值
// 因?yàn)樾薷哪硞€(gè)屬性值 or Object.assign修改,地址值都沒(méi)變,都是從同一個(gè)對(duì)象拿數(shù)據(jù),都是新值
console.log(newValue, oldValue)
// 默認(rèn)開(kāi)啟了深度監(jiān)視
})ref或reactive對(duì)象數(shù)據(jù)的某個(gè)屬性
監(jiān)視響應(yīng)式對(duì)象中的某個(gè)屬性,且該屬性是基本類型的,要寫成函數(shù)式(可監(jiān)視的第三種數(shù)據(jù),能返回一個(gè)值的函數(shù))
// reactive 和ref創(chuàng)建都可
let info = reactive({
name: "vue", category: "js", address: {
phone: 110,
email: "123213"
}
})
// 監(jiān)視info對(duì)象的name屬性,函數(shù)式
watch(() => info.name, (newValue, oldValue) => {
// new是新值,old是舊值
console.log(newValue, oldValue)
})監(jiān)視響應(yīng)式對(duì)象中的某個(gè)屬性,且該屬性是對(duì)象類型的,可以直接寫也可以寫函數(shù)式,推薦函數(shù)式
// reactive 和ref創(chuàng)建都可
let info = reactive({
name: "vue", category: "js", address: {
phone: 110,
email: "123213"
}
})
// 直接編寫
// address中的某個(gè)屬性發(fā)生變化,可以監(jiān)視,但是整個(gè)對(duì)象替換,不會(huì)觸發(fā)監(jiān)視,即便開(kāi)啟深度監(jiān)視
watch(info.address, (newValue, oldValue) => {
console.log(newValue,oldValue)
})// 函數(shù)式
// address中的某個(gè)屬性發(fā)生變化,可以監(jiān)視,整個(gè)對(duì)象替換,也可以觸發(fā)監(jiān)視
// 若是對(duì)象監(jiān)視的是地址值,需要關(guān)注對(duì)象內(nèi)部,需要手動(dòng)開(kāi)啟深度監(jiān)視
watch(() => info.address, (newValue, oldValue) => {
console.log(newValue, oldValue)
},{deep:true})監(jiān)視多個(gè)數(shù)據(jù)
// 監(jiān)視多個(gè)數(shù)據(jù),可以放在一個(gè)數(shù)組里面
watch([() => info.address,()=>info.name], (newValue, oldValue) => {
// newValue和oldValue 是前后的整個(gè)info對(duì)象
console.log(newValue, oldValue)
},{deep:true})watchEffect
立即運(yùn)行一個(gè)函數(shù),同時(shí)響應(yīng)式地追蹤其依賴,并在依賴更改時(shí)重新執(zhí)行該函數(shù)
? watch對(duì)比watchEffect
都能監(jiān)聽(tīng)響應(yīng)式數(shù)據(jù)的變化,不同的是監(jiān)聽(tīng)數(shù)據(jù)變化的方式不同
watch:要明確指出監(jiān)視的數(shù)據(jù)
watchEffect:不用明確指出監(jiān)視的數(shù)據(jù)(函數(shù)中用到哪些屬性,那就監(jiān)視哪些屬性)
// 引入watchEffect
import {watchEffect, ref, reactive} from "vue"
let info = reactive({
name: "vue", category: "js", address: {
phone: 110,
email: "123213"
}
})
let count = ref(0)
// 初始化的時(shí)候會(huì)首先執(zhí)行一次,相當(dāng)于watch的immediate:true
const wa = watchEffect(()=>{
// 函數(shù)中用到哪些屬性,vue會(huì)分析監(jiān)視哪些屬性
if (info.name.length >10){
alert("長(zhǎng)度大于10")
// 停止監(jiān)視
wa()
}
if (count.value === 10){
alert("count")
wa()
}
})標(biāo)簽中的ref屬性
用于注冊(cè)模版引用
<template> <!-- 與vue2一樣--> <!-- 用在普通DOM標(biāo)簽上,獲取的是DOM節(jié)點(diǎn) --> <h1 ref="t">title</h1> <!-- 用在組件標(biāo)簽上,獲取的是組件實(shí)例對(duì)象--> <UserInfo ref="user"></UserInfo> <button @click="cli">按鈕</button> </template>
<script setup lang="ts">
import {ref} from "vue";
let t = ref() // ref=t的DOM節(jié)點(diǎn)對(duì)象,可以直接操作該DOM
let user = ref() // ref=user的組件實(shí)例對(duì)象
</script>通過(guò)ref獲取的組件實(shí)例對(duì)象,有一個(gè)保護(hù)措施,在父組件要訪問(wèn)子組件的哪些數(shù)據(jù),需要通過(guò)defineExpose顯示的指定
// 在子組件引入defineExpose
import {ref,defineExpose} from "vue"
// 在子組件顯示指定的數(shù)據(jù),在父組件通過(guò)ref拿到的組件實(shí)例對(duì)象才可以fang'w
defineExpose([name,age])props
和vue2的props原理一樣,主要是語(yǔ)法上的區(qū)別
父組件
<script setup lang="ts" name="App">
import UserInfo from './components/UserInfo.vue'
// 引入自定義類型約束 前面要+ type
import { type UserList} from "@/types";
import { reactive} from "vue";
let users = reactive<UserList>([
{id: "001", name: "1", age: 1},
{id: "002", name: "2", age: 2},
{id: "003", name: "3", age: 3},
]
)
</script><template> <!-- 傳遞users--> <UserInfo :list="users"></UserInfo> </template>
子組件-不約束類型
<script setup lang="ts" name="UserInfo">
import { type UserList} from "@/types";
// import {defineProps} from "vue"
// 看視頻教程defineProps需要導(dǎo)入,但是導(dǎo)入后使用有報(bào)錯(cuò),然后看資料不需要導(dǎo)入,不確定是不是和版本有關(guān)系
// 不約束類型
defineProps(["list"])
// 如果使用變量接收defineProps,返回值是{傳遞的key:傳遞的value}
</script><template>
<ul>
<li v-for="user of list" :key="user.id">{{ user.name }}</li>
</ul>
</template>子組件-約束類型
// 接收l(shuí)ist參數(shù),類型是UserList
defineProps<{ list: UserList }>()子組件-可選以及設(shè)置默認(rèn)值
// 使用withDefaults設(shè)置默認(rèn)值
withDefaults(
// 第一個(gè)參數(shù)defineProps接收參數(shù),?可行參數(shù)是ts語(yǔ)法
defineProps<{ list?: UserList }>(),
// 第二個(gè)參數(shù)是一個(gè)對(duì)象,給可選參數(shù)設(shè)置默認(rèn)值
{
list: () => [{id: "001", name: "1", age: 1}]
}
)vue3的生命周期鉤子
<script setup lang="ts" name="UserInfo">
// setup函數(shù)是創(chuàng)建階段,在setup語(yǔ)法糖里相當(dāng)于進(jìn)入了創(chuàng)建階段
import {onBeforeMount, onBeforeUnmount, onBeforeUpdate, onMounted, onUnmounted, onUpdated} from "vue";
// 掛載前
onBeforeMount(() => {
console.log("掛載前")
})
// 掛載完畢
onMounted(() => {
console.log("掛載完畢")
})
// 更新前
onBeforeUpdate(() => {
console.log("更新前")
})
// 更新完畢
onUpdated(() => {
console.log("更新完畢")
})
// 卸載前,等同于vue2的銷毀
onBeforeUnmount(() => {
console.log("卸載前")
})
// 卸載后
onUnmounted(() => {
console.log("卸載后")
})
</script>自定義hooks
本質(zhì)是一個(gè)函數(shù),把
setup函數(shù)中使用的Composition API進(jìn)行了封裝,類似于vue2.x中的mixin。自定義
hook的優(yōu)勢(shì):復(fù)用代碼, 讓setup中的邏輯更清楚易懂使用use作為hooks文件名的前綴(非強(qiáng)制,社區(qū)慣例)
編寫hooks文件
import {ref, onMounted, computed} from "vue";
// 整體hooks邏輯寫在一個(gè)函數(shù)里
export default function () {
// 定義響應(yīng)式數(shù)據(jù)
let info = ref<number>(1)
// 獲取數(shù)據(jù)
function getDetail() {
return info
}
// 修改數(shù)據(jù)
function setDetail(value: number) {
info.value = value
}
// 可以寫鉤子方法
onMounted(() => {
console.log("掛載完畢")
})
// 可以寫計(jì)算屬性
let doubleInfo = computed<number>(() => {
return info.value * 2
})
// 其他的監(jiān)視屬性等等vue方法屬性都可以在這里編寫
// 將這些方法組合成一個(gè)hooks,然后提供給組件使用
// 向外部提供東西
return {getDetail, setDetail,doubleInfo}
}使用hooks
import useDetail from "@/hooks/useDetail";
const {getDetail,setDetail,doubleInfo} = useDetail()
getDetail()
setDetail(6)到此這篇關(guān)于vue3 setup中使用響應(yīng)式的文章就介紹到這了,更多相關(guān)vue3 setup使用響應(yīng)式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Vue源碼解析之?dāng)?shù)據(jù)響應(yīng)系統(tǒng)的使用
這篇文章主要介紹了Vue源碼解析之?dāng)?shù)據(jù)響應(yīng)系統(tǒng)的使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04
基于vue 動(dòng)態(tài)加載圖片src的解決方法
下面小編就為大家分享一篇基于vue 動(dòng)態(tài)加載圖片src的解決方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-02-02
vue動(dòng)態(tài)合并單元格并添加小計(jì)合計(jì)功能示例
這篇文章主要給大家介紹了關(guān)于vue動(dòng)態(tài)合并單元格并添加小計(jì)合計(jì)功能的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11
vue項(xiàng)目在安卓低版本機(jī)顯示空白的原因分析(兩種)
本文給大家?guī)?lái)vue項(xiàng)目在安卓低版本機(jī)顯示空白的原因分析,根據(jù)各自需求給大家?guī)?lái)了兩種原因分析,大家可以參考下2018-09-09
vue項(xiàng)目實(shí)現(xiàn)多語(yǔ)言切換的思路
這篇文章主要介紹了vue項(xiàng)目實(shí)現(xiàn)多語(yǔ)言切換的思路,幫助大家完成多語(yǔ)言翻譯,感興趣的朋友可以了解下2020-09-09
vue路由傳參之使用query傳參頁(yè)面刷新數(shù)據(jù)丟失問(wèn)題解析
這篇文章主要介紹了vue路由傳參使用query傳參頁(yè)面刷新數(shù)據(jù)丟失問(wèn)題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-04-04
Vue3實(shí)戰(zhàn)學(xué)習(xí)配置使用vue?router路由步驟示例
這篇文章主要為大家介紹了Vue3實(shí)戰(zhàn)學(xué)習(xí)配置使用vue?router路由步驟示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06
Vue3處理大數(shù)據(jù)量渲染和優(yōu)化的方法小結(jié)
在現(xiàn)代Web應(yīng)用中,隨著用戶數(shù)據(jù)和交互的復(fù)雜性增加,如何高效地處理大數(shù)據(jù)量渲染成為了前端開(kāi)發(fā)的重要環(huán)節(jié),本文將以Vue 3為例,探討如何優(yōu)化大數(shù)據(jù)量渲染,提升應(yīng)用性能,需要的朋友可以參考下2024-07-07
使用vue-cli3 創(chuàng)建vue項(xiàng)目并配置VS Code 自動(dòng)代碼格式化 vue語(yǔ)法高亮問(wèn)題
這篇文章主要介紹了使用vue-cli3 創(chuàng)建vue項(xiàng)目,并配置VS Code 自動(dòng)代碼格式化 vue語(yǔ)法高亮問(wèn)題,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-05-05

