觀察下面一段代碼,學習響應式基礎的全部內容
<template><div><div>將下面的msg屬性放到上面來:{{ msg }}</div><button @click="count++">{{ count }}</button><button @click="object.count.value++">{{ object.count.value }}</button><button @click="open">點擊變豬</button><button @click="addAge">長大一歲</button><a :href="hrefValue" id="herfValue">Dom更新的時間:{{ hrefValue }}</a><button @click="changeUrl">更改上面url</button><button @click="addAgeReactive">長大一歲{{ age.count }}</button></div>
</template><script lang="ts" setup>
import { nextTick } from 'vue'
import { ref } from 'vue'
import { reactive } from 'vue'
//綁定上方的學無止境
const msg = ref('學無止境')
//綁定上方的count
const count = ref(0)
//如果這么寫count是不能被解包的
const object = { count: ref(1) }
//如果標簽中存在object.count++則不會被解包
//必須使用object.count.value++才能//下面代買會輸出學無止境
console.log(msg.value)
//綁定上方的變豬
function open() {msg.value = '豬'
}
//綁定一個對象
const user = ref({userName: '張三',age: 10
})
//增加一歲
function addAge() {user.value.age++
}
const hrefValue = ref('www.baidu.com')
async function changeUrl() {hrefValue.value = 'www.json.cn'let element = document.getElementById('herfValue')if (element) {console.log(element.getAttribute('href'))}await nextTick//他在執行了上面的nextTick方法之后才會改變值if (element) {console.log(element.getAttribute('href'))}
}
const age = reactive({ count: 0 })
//又增加一歲
function addAgeReactive() {//reactive創建的不需要寫valueage.count++
}
let raw = {}
const proxy = reactive(raw)
//true
console.log(reactive(raw) === proxy)
//false
console.log(proxy === raw)
//即便返回
const proxy2 = reactive({})
proxy2.nested = raw
//返回false
console.log(proxy2.nested === raw)
proxy2.nested = proxy
//返回true
console.log(proxy2.nested === proxy)//reactive局限性
let state = reactive({ count: 0 })// 上面的 ({ count: 0 }) 引用將不再被追蹤
// (響應性連接已丟失!) 重復賦值
state = reactive({ count2: 1 })
// 當解構時,count 已經與 state.count 斷開連接
let { count2 } = state
// 不會影響原始的 state
count2++// 該函數接收到的是一個普通的數字
// 并且無法追蹤 state.count 的變化
// 我們必須傳入整個對象以保持響應性
//找不到count 這個屬性,所以代理對象之間不能相互賦值
callSomeFunction(state.count2)function callSomeFunction(count) {//返回0console.log(count)
}//Ref自動解包
const name = ref('張三')
const bigName = reactive({ name })
//輸出的實際是ref("張三")
console.log(bigName.name)
//ref("張三") = "李四"
bigName.name = '李四'
//返回李四
console.log(name.value)
//返回李四
console.log(bigName.name)//如果將一個新的 ref 賦值給一個關聯了已有 ref 的屬性,那么它會替換掉舊的 ref:
const otherName = ref("王五")
bigName.name = otherName
//返回王五
console.log(bigName.name)
//返回李四
console.log(name.value) //與 reactive 對象不同的是,當 ref 作為響應式數組或原生集合類型 (如 Map) 中的元素被訪問時,它不會被解包:
const books = reactive([ref('Vue 3 Guide')])
// 這里需要 .value
console.log(books[0].value)const map = reactive(new Map([['count', ref(0)]]))
// 這里需要 .value
console.log(map.get('count').value)</script><style scoped>
</style>
他執行之后產生的頁面是這樣的
知識點1:ref()
當我們在script引入
<script lang="ts">import { ref } from 'vue'
</script>
我們就可以使用ref來代理一些變量,還記得我們在vue2中的寫法嗎?通過選項式API,我們在return中的變量都可以被vue雙向綁定,而在vue3中我們可以使用更加便捷的方式來操作變量,
<script lang="ts">
import { ref } from 'vue'
setup(){const msg = ref('學無止境')return {msg}
}
</script>
在上面return中的內容就相當于vue2中任何return、methods等一切可以雙向綁定的內容,是的,他也可以代理方法
<script lang="ts">
import { ref } from 'vue'
setup(){const msg = ref('學無止境')function open() {msg.value = '豬'}return {openmsg}
}
</script>
這樣他就可以代理方法了,我們看到一個msg.value,什么意思呢?ref本質是一個對象,.value可以對對象進行解包,這樣就可以獲取msg的內容。當然如果你綁定到html代碼里面,這個東西是會自動解包的
<div>將下面的msg屬性放到上面來:{{ msg }}</div>
它也可以綁定對象等
<template><button @click="addAge">長大一歲</button>
</template>
<script lang="ts">
setup(){//綁定一個對象const user = ref({userName: '張三',age: 10})//增加一歲function addAge() {user.value.age++}return {user,addAge}
}
</script>
如果你想分別獲取ref變化之前和之后的值,nextTick可以幫助到你
<template><a :href="hrefValue" id="herfValue">Dom更新的時間:{{ hrefValue }}</a><button @click="changeUrl">更改上面url</button>
</template>
<script lang="ts">
import { nextTick } from 'vue'
import { ref } from 'vue'
setup(){const hrefValue = ref('www.baidu.com')async function changeUrl() {hrefValue.value = 'www.json.cn'let element = document.getElementById('herfValue')if (element) {console.log(element.getAttribute('href'))}await nextTick//他在執行了上面的nextTick方法之后才會改變值if (element) {console.log(element.getAttribute('href'))}}return {changeUrl,hrefValue }
}
</script>
上面的代碼在? ?await nextTick之前,他的值事還沒有變化的,所以你hrefValue.value之后,是不能快速的獲取到他的值的
寫了這么多,我們發現每次都需要最后都要return,每次都需要寫setup函數不方便,那么我們可以簡化一些代碼,例如上面那段代碼,我們可以簡化成
<template><a :href="hrefValue" id="herfValue">Dom更新的時間:{{ hrefValue }}</a><button @click="changeUrl">更改上面url</button>
</template>
<script lang="ts" setup>const hrefValue = ref('www.baidu.com')async function changeUrl() {hrefValue.value = 'www.json.cn'let element = document.getElementById('herfValue')if (element) {console.log(element.getAttribute('href'))}await nextTick//他在執行了上面的nextTick方法之后才會改變值if (element) {console.log(element.getAttribute('href'))}}}
</script>
這樣就可以不寫setup和return函數了,他會自己檢測需要return的東西,函數或者變量都會被返回。
知識點2:?reactive()
reactive的使用和ref基本類似
const age = reactive({ count: 0 })
//又增加一歲
function addAgeReactive() {//reactive創建的不需要寫valueage.count++
}
如上面所示,他不需要進行寫.value就可以對變量進行++操作
在比較相等性,也就是引用上,可能與我們想象的不同
let raw = {}
const proxy = reactive(raw)
//會引用同一個對象,返回true
console.log(reactive(raw) === proxy)
//封裝的對象和原始對象不一樣,返回false
console.log(proxy === raw)
const proxy2 = reactive({})
proxy2.nested = raw
//封裝對象的屬性被賦值普通對象,返回false
console.log(proxy2.nested === raw)
proxy2.nested = proxy
//封裝對象的屬性被賦值封裝對象,返回true
console.log(proxy2.nested === proxy)
區別于vue2,return中的對象只會雙向綁定,但是vue3中這么開放肯定會存在覆蓋的現象
//reactive局限性
let state = reactive({ count: 0 })// 上面的 ({ count: 0 }) 引用將不再被追蹤
// (響應性連接已丟失!) 重復賦值
state = reactive({ count2: 1 })
// 當解構時,count 已經與 state.count 斷開連接
let { count2 } = state
// 不會影響原始的 state
count2++// 該函數接收到的是一個普通的數字
// 并且無法追蹤 state.count 的變化
// 我們必須傳入整個對象以保持響應性
//找不到count 這個屬性,所以代理對象之間不能相互賦值
callSomeFunction(state.count2)function callSomeFunction(count) {//返回0console.log(count)
}
如上state又被重復賦值了,那么他最后指向的是后者?當解構時,count 已經與 state.count 斷開連接,即便++,也只是普通變量的++,不能改變count2的值
知識點3:ref自動解包
//Ref自動解包
const name = ref('張三')
const bigName = reactive({ name })
//輸出的實際是ref("張三")
console.log(bigName.name)
//ref("張三") = "李四"
bigName.name = '李四'
//返回李四
console.log(name.value)
//返回李四
console.log(bigName.name)//如果將一個新的 ref 賦值給一個關聯了已有 ref 的屬性,那么它會替換掉舊的 ref:
const otherName = ref("王五")
bigName.name = otherName
//返回王五
console.log(bigName.name)
//返回李四
console.log(name.value) //與 reactive 對象不同的是,當 ref 作為響應式數組或原生集合類型 (如 Map) 中的元素被訪問時,它不會被解包:
const books = reactive([ref('Vue 3 Guide')])
// 這里需要 .value
console.log(books[0].value)const map = reactive(new Map([['count', ref(0)]]))
// 這里需要 .value
console.log(map.get('count').value)
就是有時候需要寫.value,有時候不需要,在ref對象被當作一個對象傳入時候是自動解包的,他在其他對象里面則無法自動解包
???關注公眾號:資小庫,問題快速答疑解惑