文章目錄
- 前言
- 一、setup
- 1.定義
- 2.作用
- 3.響應式數據
- 1.ref
- 2.reactive
- 3.ref與reactive的區別
- 4.toRefs
- 5.computed
- 二、Watch
- 1.監視ref:基本數據
- 2.監視ref:對象數據
- 3.監視reactive:對象數據。
- 4.監視ref或reactive中某個屬性
- 5.監視多個屬性
- 總結
前言
- setup、響應式數據的幾個函數、watch監聽。
一、setup
1.定義
- 它是一個新的組件選項,與以前的data、methods標簽相同的地位。
2.作用
- 可以在setup里面定義變量、方法,同時返回值可以使用類似于lambda表達式的簡便寫法。
關鍵問題1:在setup中能否讀到以前data選項或methods選項里面的數據?
不能,淺顯的理解一下就是。因為setup沒有維護this對象,無法調用。
關鍵問題2:在data選項或methods選項中可以讀到setup中的數據?
可以,需要使用this進行調用。
setup示例:
export default {name:'Person', // 組件名// 1.setup能和methods data共存 // 2.data里面能不能讀到setup里面的數據?// >>可以,使用this.變量進行讀取// 3.但是setup不可以讀到data里面的數據// 4.setup是一個全新的配置項 它的優先級比vue2中的beforeCreate的優先級更高// 5.它不存在this,沒有維護this對象setup(){// 1.數據 ---> data選項let name = '張三'let age = 18let tel = '1388888888'// 2.方法function changeName () {// 注意:此時的數據不是響應式的// 雖然改了但是頁面不會有變化 name = 'zhang-san'}function changeAge () {age += 1}function showTel () {alert(tel)}// 2.通過返回值進行返回數據 可交可不交return {name,age,changeName,changeAge,showTel}// return ()=>'哈哈' 直接返回 setup的返回值也可以是個渲染函數}
}
語法糖:
- 可以直接寫在script標簽里,自動返回變量。以上的寫法等價于下面的寫法。
關鍵問題3:如果說需要自定義命名組件名需要單獨設置,但是默認是與文件名一致。
關鍵問題4:如果說要想基本數據類型是響應式的,需要導入ref,將響應式數據用ref()框起來,需要在改變的時候使用.value進行修改。因為在標簽里的變量返回值是一個RefImpl實例對象,也就是返回的數據用對象封裝起來了,里面的數據就需要.value來進行調用。
<!-- 需要單獨設置組件名的話可以在這里設置 就不使用插件了 -->
<script lang="ts">
export default {name:'Person123', // 組件名
}
</script><script lang="ts" setup>
import {ref} from 'vue'let name = ref('張三')let age = ref(18)let tel = '1388888888'function changeName () {name.value = 'zhang-san'}function changeAge () {age.value += 1}function showTel () {alert(tel)}
</script>
3.響應式數據
1.ref
- ref是一個響應式的API,用于創建一個響應式的引用,通常用于響應式基本數據類型,也可以用于對象類型的響應。
- 使用的時候將需要響應式的數據導入ref,然后用ref()包裹起來,然后在需要進行修改的時候調用數據.value進行修改。以上示例已經展示了ref的基本數據類型響應。
- 返回的是一個Proxy代理對象。
ref對象類型響應:
<template><div class="car"><h2>品牌:{{ car.brand }}</h2><h2>價格:{{ car.price }}</h2><ul><li v-for="c in cars" :key="c.name">車名:{{ c.name }},價格:{{ c.price }}</li></ul><button @click="changePrice">修改價格</button></div>
</template><script lang="ts">
export default {name:'Car',
}
</script><script lang="ts" setup>// 1.導入refimport {ref} from 'vue'// 2.用ref包裹起來let car = ref({brand:'保時捷',price:100,})// 對象數組let cars = ref([{name:'奔馳',price:100},{name:'法拉利',price:1000},])// 3.直接修改function changePrice() {car.value.price += 10 }console.log(car)
</script><style scoped>.car {background-color: skyblue;box-shadow: 0 0 10px;border-radius: 10px;padding: 20px;}.button {margin: 0 5px;}
</style>
- 它的外層使用ref包裹起來的,內部是reactive處理的。需要先用value讀到對象后再進行操作才可以,包括ref里面包含了數組對象,需要用value去讀到數組對象后在進行索引等其他操作。
<template><div class="car"><h2>品牌:{{ car.brand }}</h2><h2>價格:{{ car.price }}</h2><ul><li v-for="c in cars" :key="c.name">車名:{{ c.name }},價格:{{ c.price }}</li></ul><button @click="changePrice">修改價格</button></div>
</template><script lang="ts">
export default {name:'Car',
}
</script><script lang="ts" setup>// 1.導入reactiveimport {ref} from 'vue'// 2.用ref包裹起來let car = ref({brand:'保時捷',price:100,})// 對象數組let cars = ref([{name:'奔馳',price:100},{name:'法拉利',price:1000},])// 3.直接修改function changePrice() {car.value.price += 10 }console.log(car)
</script><style scoped>.car {background-color: skyblue;box-shadow: 0 0 10px;border-radius: 10px;padding: 20px;}.button {margin: 0 5px;}
</style>
2.reactive
- reactive也是響應式API,只能用于創建一個響應式對象。
- 使用的時候需要導入reactive,然后用reactive包裹起來,然后直接修改即可。
返回的也是一個Proxy代理對象。
注意不用.value。
reactive響應對象類型:
<template><div class="car"><h2>品牌:{{ car.brand }}</h2><h2>價格:{{ car.price }}</h2><button @click="changePrice">修改價格</button></div>
</template><script lang="ts">
export default {name:'Car',
}
</script><script lang="ts" setup>// 1.導入reactiveimport {reactive} from 'vue'// 2.用reactive包裹起來let car = reactive({brand:'保時捷',price:100,})// 3.直接修改function changePrice() {// 4.不用加.value了car.price += 10}
</script><style scoped>.car {background-color: skyblue;box-shadow: 0 0 10px;border-radius: 10px;padding: 20px;}.button {margin: 0 5px;}
</style>
數組代理對象:
- v-for類似于我們寫的mybatis的xml方式的sql語句里面的forEach,這里表示遍歷cars,:keys表示能確定每一個數據的主鍵元素,同樣需要用reactive來括起來,訪問元素就要用c來訪問。
<template><div class="car"><ul><li v-for="c in cars" :key="c.name">車名:{{ c.name }},價格:{{ c.price }}</li></ul></div>
</template><script lang="ts">
export default {name:'Car',
}
</script><script lang="ts" setup>// 1.導入reactiveimport {reactive} from 'vue'// 2.用reactive包裹起來// 對象數組let cars = reactive([{name:'奔馳',price:100},{name:'法拉利',price:1000},])
</script><style scoped>.car {background-color: skyblue;box-shadow: 0 0 10px;border-radius: 10px;padding: 20px;}.button {margin: 0 5px;}
</style>
3.ref與reactive的區別
區別1:ref用來生成響應式數據的時候,需要用.value來訪問。
區別2:ref能夠修飾基本類型、對象類型的響應式數據。
總結:基本類型用ref,層級不深的對象使用ref。
總結:層級深的使用reactive。
4.toRefs
作用:能夠將reactive包裹的對象響應式數據解構,能夠將它的每一個字段變成ref對象。
實質:將某個對象的字段結構,將該字段與對象里的字段變成一摸一樣的數據,意思是調用toRefs后我們可以修改對象的字段了。
<template><div class="person"><h2>{{ name }}</h2><h2>{{ age }}</h2><button @click="changeAge">修改年齡</button><button @click="changeName">修改名字</button></div>
</template><script lang="ts">
export default {name:'ToRefs',
}
</script><script lang=ts setup>import {ref,reactive,toRefs} from 'vue'let person = reactive({name:"kkk",age:999,})let {name, age} = toRefs(person)function changeName() {name.value = name.value + "k"}function changeAge() {age.value += 1}
</script><style scoped>.person {background-color: skyblue;box-shadow: 0 0 10px;border-radius: 10px;padding: 20px;}.button {margin: 0 5px;}
</style>
5.computed
定義:計算屬性,基于響應式數據計算響應值。
使用:需要get和set方法。像jv里的getter和setter。
v-model:數據雙向綁定。
const:明確聲明不可變數據。
const [str1,str2] = val.split(‘’-‘’) :數組也能解構定義。
<template><div class="person">姓:<input type="text" v-model="firstName"> <br>名:<input type="text" v-model="lastName"> <br><!-- v-model 是 Vue 提供的雙向數據綁定指令,主要用于 <input>、<select>、<textarea> 等表單元素,實現數據與視圖的自動同步。 -->全名:<span>{{ fullname }}</span> <br>修改:<button @click="changeFullName"></button></div>
</template><script lang="ts">
export default {name:"Compute",
}
</script><script setup lang="ts">import {ref,reactive, computed} from 'vue'let firstName = ref("jo")let lastName = ref("ny")// 變成一個可讀可寫的計算屬性let fullname = computed({get(){return firstName.value.slice(0,1).toUpperCase() + firstName.value.slice(1) + "-" + lastName.value},set(val){// 數組也能解構賦值const [str1,str2] = val.split("-")firstName.value = str1lastName.value = str2}})function changeFullName() {fullname.value = "gy-ro"}
</script><style scoped>.person {background-color: skyblue;box-shadow: 0 0 10px;border-radius: 10px;padding: 20px;}.button {margin: 0 5px;}
</style>
二、Watch
- 它能夠監視數據.。
注意1:需要監視的值不需要加.value,因為自動解包。
注意2:調用watch返回值是一個監視停止器,再次調用就會停止監視。
注意3:它只監視4種數據。函數返回值,ref、reactive和它們的數組。
1.監視ref:基本數據
<template><div class="person"><h1>監視數據</h1><h1>當前數據求和為:{{ sum }}</h1><button @click="changeSum"></button></div>
</template><script lang="ts">
export default { // 實際上這里要縮進這個大括號一下才不會報錯name:"Watch",
}
</script>
<script lang="ts" setup>
import {ref, watch} from 'vue'
// 需要用ref或reactive包裹起來let sum = ref(0)function changeSum(){sum.value += 1}// 監視const stopWatch = watch(sum, (nv,ov)=>{console.log("sum變化了", nv, ov)if(nv >= 10) {stopWatch() // 如果newValue大于等于10就停止監視 stopWatch()表示停止監視}})
</script>
2.監視ref:對象數據
- 監視用ref包裹的對象數據需要手動開啟深度監視。
- 監視的是地址,整個對象,只有整個對象改變的時候才會觸發監視器。
- 如果想要深度監視,需要手動添加深度監視。
- {immediate:true}:添加在深度監視后面。表示不管你改沒改,先執行一次箭頭函數。它提醒的是舊的引用,如果沒改變,那就還是新的那個對象,已經改了。
- 實際上開發不管舊值。
參數1:被監視的數據。
參數2:監視的回調函數。
參數3:配置對象。
實質:改的是它的引用。
<template><div class="person"><h1>情況二:監視【ref】定義的【對象類型】數據</h1><h2>姓名:{{ person.name }}</h2><h2>年齡:{{ person.age }}</h2><button @click="changeName">修改名字</button><button @click="changeAge">修改年齡</button><button @click="changePerson">修改整個人</button></div></template><script lang="ts">
export default {name:"Watch2",
}</script><script lang="ts" setup>import {ref,watch} from 'vue'// 數據let person = ref({name:'張三',age:18,})// 方法function changeName(){person.value.name += '~'}function changeAge(){person.value.age += 1}function changePerson(){person.value = {name:'李四', age:90}}/* 監視,情況一:監視【ref】定義的【對象類型】數據,監視的是對象的地址值,若想監視對象內部屬性的變化,需要手動開啟深度監視watch的第一個參數是:被監視的數據watch的第二個參數是:監視的回調watch的第三個參數是:配置對象(deep、immediate等等.....) */watch(person,(nv,ov)=>{console.log('person變化了',nv,ov)}, {deep:true})</script>
3.監視reactive:對象數據。
- 默認開啟深度監視。且關不掉哦。
修改對象: Object.assign(person,{name:‘李四’,age:80})。
第一個參數是要改的對象,第二個參數是要改的內容。
實質:沒改變原引用,只覆蓋了值。
<template><div class="person"><h1>情況三:監視【reactive】定義的【對象類型】數據</h1><h2>姓名:{{ person.name }}</h2><h2>年齡:{{ person.age }}</h2><button @click="changeName">修改名字</button><button @click="changeAge">修改年齡</button><button @click="changePerson">修改整個人</button><hr><h2>測試:{{obj.a.b.c}}</h2><button @click="test">修改obj.a.b.c</button></div></template><script lang="ts" setup name="Person">import {reactive,watch} from 'vue'// 數據let person = reactive({name:'張三',age:18})let obj = reactive({a:{b:{c:666}}})// 方法function changeName(){person.name += '~'}function changeAge(){person.age += 1}function changePerson(){Object.assign(person,{name:'李四',age:80})}function test(){obj.a.b.c = 888}// 監視,情況三:監視【reactive】定義的【對象類型】數據,且默認是開啟深度監視的watch(person,(nv,ov)=>{console.log('person變化了',nv,ov)})watch(obj,(nv,ov)=>{console.log('Obj變化了',nv,ov)})</script>
4.監視ref或reactive中某個屬性
- 當我們直接修改的時候直接把原對象的地址改了,在watch傳入的第一個參數傳遞的時候就要看地址到底是誰的,可能是原對象的可能是已經改了的。
- 總之一句話,如果我們只想監聽對象的其中某個屬性,將他寫成箭頭函數形式,并開啟深度監聽,記住就行。
<template><div class="person"><h1>情況四:監視【ref】或【reactive】定義的【對象類型】數據中的某個屬性</h1><h2>姓名:{{ person.name }}</h2><h2>年齡:{{ person.age }}</h2><h2>汽車:{{ person.car.c1 }}、{{ person.car.c2 }}</h2><button @click="changeName">修改名字</button><button @click="changeAge">修改年齡</button><button @click="changeC1">修改第一臺車</button><button @click="changeC2">修改第二臺車</button><button @click="changeCar">修改整個車</button></div>
</template><script lang="ts" setup name="Person">import {reactive,watch} from 'vue'// 數據let person = reactive({name:'張三',age:18,car:{c1:'奔馳',c2:'寶馬'}})// 方法function changeName(){person.name += '~'}function changeAge(){person.age += 1}function changeC1(){person.car.c1 = '奧迪'}function changeC2(){person.car.c2 = '大眾'}function changeCar(){person.car = {c1:'雅迪',c2:'愛瑪'}}// 監視,情況四:監視響應式對象中的某個屬性,且該屬性是基本類型的,要寫成函數式/* watch(()=> person.name,(newValue,oldValue)=>{console.log('person.name變化了',newValue,oldValue)}) */// 監視,情況四:監視響應式對象中的某個屬性,且該屬性是對象類型的,可以直接寫,也能寫函數,更推薦寫函數watch(()=>person.car,(newValue,oldValue)=>{console.log('person.car變化了',newValue,oldValue)},{deep:true})
</script>
5.監視多個屬性
- 多個屬性放數組里,說白了如果是單純的監聽某一個屬性,寫成箭頭函數形式,如果監聽某一個對象,那就直接寫就行了。
<template><div class="person"><h1>情況五:監視上述的多個數據</h1><h2>姓名:{{ person.name }}</h2><h2>年齡:{{ person.age }}</h2><h2>汽車:{{ person.car.c1 }}、{{ person.car.c2 }}</h2><button @click="changeName">修改名字</button><button @click="changeAge">修改年齡</button><button @click="changeC1">修改第一臺車</button><button @click="changeC2">修改第二臺車</button><button @click="changeCar">修改整個車</button></div>
</template><script lang="ts" setup name="Person">import {reactive,watch} from 'vue'// 數據let person = reactive({name:'張三',age:18,car:{c1:'奔馳',c2:'寶馬'}})// 方法function changeName(){person.name += '~'}function changeAge(){person.age += 1}function changeC1(){person.car.c1 = '奧迪'}function changeC2(){person.car.c2 = '大眾'}function changeCar(){person.car = {c1:'雅迪',c2:'愛瑪'}}// 監視,情況五:監視上述的多個數據watch([()=>person.name,person.car],(newValue,oldValue)=>{console.log('person.car變化了',newValue,oldValue)},{deep:true})</script>
總結
- 今天學了ref、reactive、toRefs、watch監聽的五大情況。