vue3?setup中使用響應(yīng)式的方法
基本類型的響應(yīng)式數(shù)據(jù)
在 Vue 3 中,
ref
是一個函數(shù),用于創(chuàng)建響應(yīng)式的數(shù)據(jù)。它主要用于處理基本類型(如數(shù)字、字符串、布爾值等)的數(shù)據(jù)響應(yīng)式
當(dāng)我們調(diào)用 ref 函數(shù)時,會返回一個包含一個 .value 屬性的對象。這個對象會被轉(zhuǎn)換成 Proxy 對象,通過攔截 getter 和 setter 操作,實現(xiàn)對 .value 屬性的監(jiān)聽。當(dāng)讀取 .value 屬性時,會觸發(fā) getter操作,將 .value 屬性的值返回。當(dāng)修改 .value 屬性時,會觸發(fā) setter操作,將新的值賦給 .value 屬性
<script setup lang="ts" name="UserInfo"> // 導(dǎo)入ref import {ref} from "vue" // 需要讓哪個數(shù)據(jù)是響應(yīng)式的,就給哪個數(shù)據(jù)使用ref let age = ref(18) let name = ref("vue3") // 不需要響應(yīng)式 let address:string = "Beijing" // ref返回的是一個響應(yīng)式對象,里面的value是具體的值 // 在template模版中使用 例如age,不需要age.value,模版會自動.value解析 // 但是在ts、js代碼中使用,需要.value function setAge(){ age.value = 20 // 將value改成20,響應(yīng)式修改 } </script>
<template> {{ age }} {{ name }} {{address}} <button @click="setAge">修改年齡</button> </template>
ref也可以用于處理對象和數(shù)組,但對于復(fù)雜類型,reactive
函數(shù)可能更加合適
<script setup lang="ts" name="UserInfo"> import {ref} from "vue" // 響應(yīng)式對象數(shù)據(jù) // ref處理對象的原理-底層調(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>
對象類型的響應(yīng)式數(shù)據(jù)
reactive
是一個用于創(chuàng)建響應(yīng)式對象的函數(shù)。它主要用于處理復(fù)雜的數(shù)據(jù)類型,如對象和數(shù)組,使得這些數(shù)據(jù)成為響應(yīng)式數(shù)據(jù),即當(dāng)數(shù)據(jù)的內(nèi)容發(fā)生變化時,與之綁定的組件模板會自動更新
當(dāng)我們調(diào)用 reactive 函數(shù)時,會將傳入的普通 JavaScript 對象轉(zhuǎn)換為一個 Proxy 對象,通過攔截 getter 和 setter 操作,實現(xiàn)對整個對象的監(jiān)聽。當(dāng)讀取對象的屬性時,會觸發(fā) getter操作,返回對應(yīng)屬性的值。當(dāng)修改對象的屬性時,會觸發(fā) setter操作,將新的值賦給對應(yīng)的屬性
<script setup lang="ts" name="UserInfo"> // 導(dǎo)入reactive import {reactive} from "vue" // 需要讓哪個對象是響應(yīng)式的,就給哪個對象使用ref // 響應(yīng)式對象 let info = reactive({name:"vue3",age:18}) // 非響應(yīng)式對象 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可以用來定義基本數(shù)據(jù)類型、對象數(shù)據(jù)類型
reactive只能用來定義對象數(shù)據(jù)類型
若需要一個基本類型的響應(yīng)式數(shù)據(jù),必須使用ref
若需要一個響應(yīng)式對象,層級不深,ref、reactive都可以。
若需要一個響應(yīng)式對象,且層級較深,推薦使用reactive
ref創(chuàng)建的變量必須使用.value
reactive重新分配一個新對象,會失去響應(yīng)式,可以使用Object.assign整體替換
let info = reactive({name: "vue3", age: 18}) // info = {name:"vue2"},給info重新分配對象,會失去響應(yīng)式 // info = reactive({name:"vue2"}) 不能使用該方式重新分配響應(yīng)式對象,使用該方式后,不是原先的響應(yīng)式info是一個新的響應(yīng)式info,頁面不更新 // 使用這種方式重新分配對象 Object.assign(info,{name:"vue2",age:20})
如果是使用ref創(chuàng)建的響應(yīng)式對象,重新分配一個對象,可以直接分配
let info = ref({name: "vue3", age: 18}) // 直接賦值替換,也是響應(yīng)式的,通過.value拿到替換,.value拿到的就是響應(yīng)式的 info.value = {name:"3",age:20} // 響應(yīng)式基本數(shù)據(jù)類型不能直接這樣修改,需要通過.value // 使用該方式相當(dāng)于創(chuàng)建了一個新的響應(yīng)式,而不是原先的響應(yīng)式,頁面是跟原先的響應(yīng)式關(guān)聯(lián) let count = ref(10) count = ref(20)
toRefs和toRef
- 作用:將一個響應(yīng)式對象中的每一個屬性,轉(zhuǎn)換為
ref
對象。- 備注:
toRefs
與toRef
功能一致,但toRefs
可以批量轉(zhuǎn)換
let info = reactive({name: "vue3", age: 18}) // 解構(gòu)賦值 let {name, age} = info function setInfo() { //頁面沒有響應(yīng)式變化 // 變化的數(shù)據(jù)是解構(gòu)出來的age,而不是info.age age += 1 }
// 解構(gòu)賦值 // 底層實現(xiàn)是將每一個屬性 使用ref進(jìn)行轉(zhuǎn)換,都是ref對象 // toRefs可以批量轉(zhuǎn)換 let {name, age} = toRefs(info) function setInfo() { // 頁面數(shù)據(jù)可以響應(yīng)式變化 age.value += 1 }
// toRef只能轉(zhuǎn)換單個 let age = toRef(info,age)
計算屬性
根據(jù)已有數(shù)據(jù)計算出新數(shù)據(jù)(和Vue2
中的computed
作用一致)
計算屬性是有緩存的,多個場景使用一個計算屬性,計算數(shù)據(jù)不發(fā)生變化,則只計算一次
- 只讀計算屬性
// 導(dǎo)入computed計算屬性,是一個函數(shù) import {computed, ref} from "vue" let name = ref("vue") let age = ref(20) // 計算屬性 // 只讀取的計算屬性,不能通過info=xxx這種方式修改info let info = computed(() => name.value + "-" + age.value)
- 可讀可修改計算屬性
// 導(dǎo)入computed計算屬性,是一個函數(shù) import {computed, ref} from "vue" let name = ref("vue") let age = ref(20) // 計算屬性 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ā)重新計算 然后生成新的info name.value = str1 age.value = Number(str2) } })
監(jiān)視屬性
- 作用:監(jiān)視數(shù)據(jù)的變化(和
Vue2
中的watch
作用一致) - 特點:
Vue3
中的watch
只能監(jiān)視以下四種數(shù)據(jù):
ref
定義的數(shù)據(jù)。
reactive
定義的數(shù)據(jù)。函數(shù)返回一個值(
getter
函數(shù))一個包含上述內(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ù) 的長度大于等于10的時候,停止監(jiān)視 if (newValue.length >=10){ // 原理:watch函數(shù)會返回一個函數(shù)。這個返回的函數(shù)實際上是一個用于清理或停止監(jiān)視操作的句柄 wa() } })
ref對象類型數(shù)據(jù)
監(jiān)視的是對象的【地址值】,若想監(jiān)視對象內(nèi)部的數(shù)據(jù),要手動開啟深度監(jiān)視
// 導(dǎo)入watch import {watch, ref} from "vue" let info = ref({name: "vue", category: "js"}) // 監(jiān)視的是對象的內(nèi)存地址的值 // info.value = {}的時候會觸發(fā),修改里面某個屬性不好觸發(fā) watch(info, (newValue, oldValue) => { // 如果修改整個對象,newValue是新對象,oldValue是舊對象 console.log(newValue, oldValue) })
watch的第三個參數(shù)是一個配置對象,deep、immediate等等
watch(info, (newValue, oldValue) => { // 如果修改某個屬性,newValue, oldValue兩個都是新值,因為他們是同一個對象 // 如果修改整個對象才會是兩個對象 console.log(newValue, oldValue) // deep開啟深度監(jiān)視,修改里面的某個屬性 、修改整個對象 都會觸發(fā) // immediate在watch函數(shù)創(chuàng)建的時候立即執(zhí)行一次回調(diào)函數(shù) },{deep:true,immediate:true})
reactive對象數(shù)據(jù)類型
監(jiān)視reactive對象,默認(rèn)開啟了深度監(jiān)視
import {watch, ref, reactive} from "vue" let info = reactive({name: "vue", category: "js"}) watch(info, (newValue, oldValue) => { // newValue, oldValue不管是修改整個對象還是某個屬性,都是新值 // 因為修改某個屬性值 or Object.assign修改,地址值都沒變,都是從同一個對象拿數(shù)據(jù),都是新值 console.log(newValue, oldValue) // 默認(rèn)開啟了深度監(jiān)視 })
ref或reactive對象數(shù)據(jù)的某個屬性
監(jiān)視響應(yīng)式對象中的某個屬性,且該屬性是基本類型的,要寫成函數(shù)式(可監(jiān)視的第三種數(shù)據(jù),能返回一個值的函數(shù))
// reactive 和ref創(chuàng)建都可 let info = reactive({ name: "vue", category: "js", address: { phone: 110, email: "123213" } }) // 監(jiān)視info對象的name屬性,函數(shù)式 watch(() => info.name, (newValue, oldValue) => { // new是新值,old是舊值 console.log(newValue, oldValue) })
監(jiān)視響應(yīng)式對象中的某個屬性,且該屬性是對象類型的,可以直接寫也可以寫函數(shù)式,推薦函數(shù)式
// reactive 和ref創(chuàng)建都可 let info = reactive({ name: "vue", category: "js", address: { phone: 110, email: "123213" } }) // 直接編寫 // address中的某個屬性發(fā)生變化,可以監(jiān)視,但是整個對象替換,不會觸發(fā)監(jiān)視,即便開啟深度監(jiān)視 watch(info.address, (newValue, oldValue) => { console.log(newValue,oldValue) })
// 函數(shù)式 // address中的某個屬性發(fā)生變化,可以監(jiān)視,整個對象替換,也可以觸發(fā)監(jiān)視 // 若是對象監(jiān)視的是地址值,需要關(guān)注對象內(nèi)部,需要手動開啟深度監(jiān)視 watch(() => info.address, (newValue, oldValue) => { console.log(newValue, oldValue) },{deep:true})
監(jiān)視多個數(shù)據(jù)
// 監(jiān)視多個數(shù)據(jù),可以放在一個數(shù)組里面 watch([() => info.address,()=>info.name], (newValue, oldValue) => { // newValue和oldValue 是前后的整個info對象 console.log(newValue, oldValue) },{deep:true})
watchEffect
立即運行一個函數(shù),同時響應(yīng)式地追蹤其依賴,并在依賴更改時重新執(zhí)行該函數(shù)
? watch
對比watchEffect
都能監(jiān)聽響應(yīng)式數(shù)據(jù)的變化,不同的是監(jiān)聽數(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) // 初始化的時候會首先執(zhí)行一次,相當(dāng)于watch的immediate:true const wa = watchEffect(()=>{ // 函數(shù)中用到哪些屬性,vue會分析監(jiān)視哪些屬性 if (info.name.length >10){ alert("長度大于10") // 停止監(jiān)視 wa() } if (count.value === 10){ alert("count") wa() } })
標(biāo)簽中的ref屬性
用于注冊模版引用
<template> <!-- 與vue2一樣--> <!-- 用在普通DOM標(biāo)簽上,獲取的是DOM節(jié)點 --> <h1 ref="t">title</h1> <!-- 用在組件標(biāo)簽上,獲取的是組件實例對象--> <UserInfo ref="user"></UserInfo> <button @click="cli">按鈕</button> </template>
<script setup lang="ts"> import {ref} from "vue"; let t = ref() // ref=t的DOM節(jié)點對象,可以直接操作該DOM let user = ref() // ref=user的組件實例對象 </script>
通過ref獲取的組件實例對象,有一個保護措施,在父組件要訪問子組件的哪些數(shù)據(jù),需要通過defineExpose顯示的指定
// 在子組件引入defineExpose import {ref,defineExpose} from "vue" // 在子組件顯示指定的數(shù)據(jù),在父組件通過ref拿到的組件實例對象才可以fang'w defineExpose([name,age])
props
和vue2的props原理一樣,主要是語法上的區(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)入后使用有報錯,然后看資料不需要導(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>
子組件-約束類型
// 接收list參數(shù),類型是UserList defineProps<{ list: UserList }>()
子組件-可選以及設(shè)置默認(rèn)值
// 使用withDefaults設(shè)置默認(rèn)值 withDefaults( // 第一個參數(shù)defineProps接收參數(shù),?可行參數(shù)是ts語法 defineProps<{ list?: UserList }>(), // 第二個參數(shù)是一個對象,給可選參數(shù)設(shè)置默認(rèn)值 { list: () => [{id: "001", name: "1", age: 1}] } )
vue3的生命周期鉤子
<script setup lang="ts" name="UserInfo"> // setup函數(shù)是創(chuàng)建階段,在setup語法糖里相當(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ì)是一個函數(shù),把
setup
函數(shù)中使用的Composition API
進(jìn)行了封裝,類似于vue2.x
中的mixin
。自定義
hook
的優(yōu)勢:復(fù)用代碼, 讓setup
中的邏輯更清楚易懂使用use作為hooks文件名的前綴(非強制,社區(qū)慣例)
編寫hooks文件
import {ref, onMounted, computed} from "vue"; // 整體hooks邏輯寫在一個函數(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("掛載完畢") }) // 可以寫計算屬性 let doubleInfo = computed<number>(() => { return info.value * 2 }) // 其他的監(jiān)視屬性等等vue方法屬性都可以在這里編寫 // 將這些方法組合成一個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)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue3?使用?vue3-video-play實現(xiàn)在線視頻播放
這篇文章主要介紹了vue3?使用?vue3-video-play?進(jìn)行在線視頻播放,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-06-06uniapp?APP中內(nèi)嵌webview的H5與APP相互通訊動態(tài)傳參代碼示例
最近外部公司的app要接入我司的uni H5項目,所以這篇文章主要給大家介紹了關(guān)于uniapp?APP中內(nèi)嵌webview的H5與APP相互通訊動態(tài)傳參的相關(guān)資料,需要的朋友可以參考下2024-04-04詳解Vue的鉤子函數(shù)(路由導(dǎo)航守衛(wèi)、keep-alive、生命周期鉤子)
這篇文章主要介紹了詳解Vue的鉤子函數(shù)(路由導(dǎo)航守衛(wèi)、keep-alive、生命周期鉤子),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-07-07