前言
這些內容是博主在學習過程中記錄下來的,有一些不重要的點就跳過了,需要時自行查詢文檔。其實V2
到V3
的學習成本不高,熟悉V2
的話,看完這篇文章就可以上手V3
。
1,setup
setup
是所有Composition API
的容器,值為一個函數。組件中所用到的數據、方法等等,均要配置在setup
中,它會在beforeCreate
之前執行一次,注意:V3
里this
不再是指向Vue
實例,訪問this
會是undefined
1.1,返回值
- 若返回一個對象,則對象中的屬性、方法, 在模板中均可以直接使用。
- 若返回一個渲染函數:則可以自定義渲染內容。
1.2,注意點
盡量不要與V2配置混用
V2
配置(data
、methos
、computed
...)中可以訪問到setup
中的屬性、方法。
但在setup
中不能訪問到V2
配置(data
、methods
、computed
...)。
如果有重名, setup
優先。
setup不能是一個async函數
因為返回值不再return
的對象, 而是promise
, 模板看不到return
對象中的屬性。(后期也可以返回一個Promise
實例,但需要Suspense
和異步組件的配合)
1.3,語法
<script>
import { ref, reactive } from 'vue'
export default {
name: 'Home',
setup(props, context) {
const title = ref('標題')
const data = reactive({
value: '哈哈哈'
})
return {
title,
data
}
}
}
</script>
1.4,setup的參數
props:值為對象,包含組件外部傳遞過來,且組件內部聲明接收了的屬性
-
context:上下文對象
- attrs: 值為對象,包含組件外部傳遞過來,但沒有在
props
配置中聲明的屬性, 相當于this.$attrs
- slots: 收到的插槽內容, 相當于
this.$slots
- emit: 分發自定義事件的函數, 相當于
this.$emit
- attrs: 值為對象,包含組件外部傳遞過來,但沒有在
2,ref 創建響應式數據
使用ref
可以創建一個包含響應式數據的引用對象(reference對象,簡稱ref對象),可以是基本類型、也可以是對象。
語法
// 創建
const xxx = ref(value)
// 使用
xxx.value
// 在模板中
<div>{{xxx}}</div>
3,reactive 創建響應式數據
定義一個對象類型的響應式數據,內部基于ES6
的Proxy
實現,通過代理對象操作源對象內部數據進行操作
語法
// 創建
const xxx = reactive({
xxx: ''
})
// 使用
xxx.xxx
4,computed 計算屬性
與V2
中computed
配置功能一致
語法
import { computed } from 'vue'
setup(){
// 簡寫語法
let fullName = computed(() => {
return person.firstName + '-' + person.lastName
})
// 完整語法
let fullName = computed({
get(){
return person.firstName + '-' + person.lastName
},
set(value){
const nameArr = value.split('-')
person.firstName = nameArr[0]
person.lastName = nameArr[1]
}
})
return fullName
}
5,watch 監聽
與V2
中watch
配置功能一致,語法有點改動
語法
- 情況一:監視
ref
定義的響應式數據
watch(sum, (newValue, oldValue) => {
console.log('sum變化了', newValue, oldValue)
}, {immediate:true})
- 情況二:監視多個
ref
定義的響應式數據
watch([sum, msg], (newValue,oldValue) => {
console.log('sum或msg變化了', newValue,oldValue)
})
- 情況三:監視
reactive
定義的響應式數據
// 若watch監視的是reactive定義的響應式數據,則無法正確獲得oldValue
// 若watch監視的是reactive定義的響應式數據,則強制開啟了深度監視
watch(person, (newValue, oldValue) => {
console.log('person變化了', newValue, oldValue)
}, { immediate:true, deep:false }) // 此處的deep配置不再奏效
- 情況四:監視
reactive
定義的響應式數據中的某個屬性
watch(() => person.job, (newValue, oldValue) => {
console.log('person的job變化了', newValue, oldValue)
}, { immediate:true, deep:true })
- 情況五:監視
reactive
定義的響應式數據中的某些屬性
watch([() => person.job, () => person.name], (newValue, oldValue) => {
console.log('person的job變化了', newValue, oldValue)
}, { immediate:true, deep:true })
- 特殊情況:此處由于監視的是
reactive
素定義的對象中的某個屬性,所以deep配置有效
watch(() => person.job, (newValue, oldValue) => {
console.log('person的job變化了', newValue, oldValue)
}, { deep:true })
6,watchEffect 監聽回調
和watch
的區別是,watch
既要指明監視的屬性,也要指明監視的回調。而watchEffect
,不用指明監視哪個屬性,監視的回調中用到哪個屬性,那就監視哪個屬性,不用寫返回值。
語法
// 回調中用到的數據只要發生變化,則直接重新執行回調
watchEffect(() => {
const x1 = sum.value
const x2 = person.age
console.log('watchEffect配置的回調執行了')
})
7,生命周期
生命周期全都寫在setup
中
7.1,改變
- beforeDestroy 改名為 beforeUnmount
- destroyed 改名為 unmounted
- beforeCreate => setup
- created => setup
- beforeMount => onBeforeMount
- mounted => onMounted
- beforeUpdate => onBeforeUpdate
- updated => onUpdated
- beforeUnmount => onBeforeUnmount
- unmounted => onUnmounted
7.2,語法
setup() {
onMounted(() => {
console.log('mounted')
})
}
8,toRef 創建ref
創建一個ref
對象,其value
值指向另一個對象中的某個屬性
語法
const state = reactive({
foo: 1,
bar: 2
})
const fooRef = toRef(state, 'foo')
// 傳遞props
export default {
setup(props) {
useSomeFeature(toRef(props, 'foo'))
}
}
9,toRefs 響應式轉換
將響應式對象轉換為普通對象,其中結果對象的每個property
都是指向原始對象相應property
的ref
語法
const state = reactive({
foo: 1,
bar: 2
})
const stateAsRefs = toRefs(state)
// 此時state和stateAsRefs是關聯的
10,shallowReactive 響應式外層轉換
只處理對象最外層屬性的響應式(淺響應式)。適用于:一個對象數據,結構比較深, 但變化時只是外層屬性變化
語法
const state = shallowReactive({
foo: 1,
nested: {
bar: 2
}
})
11,shallowRef 基本數據響應式
只處理基本數據類型的響應式, 不進行對象的響應式處理。適用于:一個對象數據,后續功能不會修改該對象中的屬性,而是生新的對象來替換
語法
const shallow = shallowRef({
greet: 'Hello, world'
})
12,readonly 響應式變只讀
讓一個響應式數據變為只讀的(深只讀),應用于不希望數據被修改時
語法
const shallow = shallowRef({
greet: 'Hello, world', // 只讀
nested: {
bar: 2 // 只讀
}
})
13,shallowReadonly 響應式變只讀
讓一個響應式數據變為只讀的(淺只讀),應用于不希望數據被修改時
語法
const shallow = shallowReadonly({
foo: 1, // 只讀
nested: {
bar: 2 // 非只讀
}
})
14,toRaw 響應式變非響應式
將一個由reactive生成的響應式對象轉為普通對象,對這個普通對象的所有操作,不會引起頁面更新。
語法
const foo = {}
const Foo = reactive(foo)
console.log(toRaw(Foo) === foo) // true
15,markRaw 標記永遠不響應式
標記一個對象,使其永遠不會再成為響應式對象,有些值不應被設置為響應式的,例如復雜的第三方類庫等,當渲染具有不可變數據源的大列表時,跳過響應式轉換可以提高性能。
語法
const foo = markRaw({})
console.log(isReactive(reactive(foo))) // false
// 嵌套在其他響應式對象中時也可以使用
const bar = reactive({ foo })
console.log(isReactive(bar.foo)) // false
16,customRef 依賴更新控制
創建一個自定義的 ref,并對其依賴項跟蹤和更新觸發進行顯式控制。它需要一個工廠函數,該函數接收track
和trigger
函數作為參數,并且應該返回一個帶有get
和set
的對象。
語法
<script>
import { customRef } from 'vue'
export default {
name: 'Home',
setup() {
// 實現防抖函數
const fn = function(value, delay = 500) {
let timeout
return customRef((track, trigger) => {
return {
get() {
track()
return value
},
set(newValue) {
clearInterval(timeout)
timeout = setTimeout(() => {
console.log(newValue)
value = newValue
trigger()
}, delay)
}
}
})
}
const keyword = fn('', 500)
return {
keyword
}
}
}
</script>
17,provide & inject 通信
實現祖與后代組件間通信,父組件有一個provide
選項來提供數據,后代組件有一個inject
選項來開始使用這些數據
語法
// 祖組件
setup(){
let car = reactive({ name:'奔馳', price:'40萬' })
provide('car', car)
}
// 后代組件
setup(props, context){
const car = inject('car')
return { car }
}
18,響應式數據的判斷
18.1,isRef
檢查一個值是否為一個ref
對象
語法
const val = ref('xxx')
isRef(val) // true
18.2,isReactive
檢查一個值是否為一個isReactive
對象
語法
const val = isReactive({})
isRef(val) // true
18.3,isReadonly
檢查一個對象是否是由readonly
創建的只讀代理
語法
const state = reactive({
name: 'John'
})
console.log(isReactive(state)) // true
18.4,isProxy
檢查對象是否是由reactive
或readonly
創建的proxy
語法
const state = reactive({
name: 'John'
})
console.log(isProxy(state)) // true
19,teleport 移動dom組件
Teleport
提供了一種干凈的方法,允許我們控制在DOM
中哪個父節點下渲染了HTML
,而不必求助于全局狀態或將其拆分為兩個組件。
語法
<teleport to="移動位置">
<div v-if="isShow" class="mask">
<div class="dialog">
<h3>我是一個彈窗</h3>
<button @click="isShow = false">關閉彈窗</button>
</div>
</div>
</teleport>
// to的格式
<teleport to="#some-id" />
<teleport to=".some-class" />
<teleport to="[data-teleport]" />
// disabled的格式
<teleport to="#popup" :disabled="displayVideoInline">
<video src="./my-movie.mp4">
</teleport>
20,Suspense 異步渲染組件
等待異步組件時先渲染一些額外內容,讓應用有更好的用戶體驗
語法
<template>
<div class="app">
<h3>我是App組件</h3>
<Suspense>
<template #default>
<Child/>
</template>
<template #fallback>
<h3>加載中.....</h3>
</template>
</Suspense>
</div>
</template>
import { defineAsyncComponent } from 'vue'
const Child = defineAsyncComponent(() => import('./components/Child.vue'))
components: {
Child
}
21,全局API調整
將全局的API,即:Vue.xxx調整到應用實例(app)上
V2的api | V3的api |
---|---|
Vue.config.xxxx | app.config.xxxx |
Vue.component | app.component |
Vue.directive | app.directive |
Vue.mixin | app.mixin |
Vue.use | app.use |
Vue.prototype | app.config.globalProperties |
22,移除api
名稱 | 現狀 |
---|---|
Vue.config.productionTip | 已移除 |
config.keyCodes | 已移除 |
$children | 已移除 |
$listeners | 已移除 |
$on | 已移除 |
$off | 已移除 |
$once | 已移除 |
filters | 已移除 |
.native | 已移除 |
23,Ref 獲取DOM
由于V3
中不在存在this
,所以ref
的獲取調整了
23.1,單個ref
語法
<div ref="Qrcode" class="qr_codeode_url" />
import { ref } from 'vue'
export default {
setup() {
const Qrcode = ref(null)
// 掛載后
onMounted(() => {
console.log(Qrcode.value)
})
return {
Qrcode
}
}
}
23.2,循環中的ref
V3
中在for
循環元素上綁定ref
將不再自動創建$ref
數組。要從單個綁定獲取多個ref
,請將ref
綁定到一個更靈活的函數上
語法
<div v-for="item in list" :ref="setItemRef"></div>
import { onBeforeUpdate, onUpdated } from 'vue'
export default {
setup() {
let itemRefs = []
const setItemRef = el => {
if (el) {
itemRefs.push(el)
}
}
onBeforeUpdate(() => {
itemRefs = []
})
onUpdated(() => {
console.log(itemRefs)
})
return {
setItemRef
}
}
}
-
itemRefs
不必是數組:它也可以是一個對象,其ref
可以通過迭代的key
被設置 - 如有需要,
itemRef
也可以是響應式的,且可以被偵聽
24,emits 自定義事件
定義一個組件可以向其父組件觸發的事件
// 在子組件中
<h1 @click="father">{{ msg }}</h1>
export default {
name: 'HelloWorld',
props: {
msg: {
type: String,
default: ''
}
},
emits: ['close'],
setup(props, { emit }) {
const father = function() {
emit('close', 'child')
}
return {
father
}
}
}
// 在父組件中
<HelloWorld :msg="msg" @click="fn" @close="fn2" />
25,$nextTick 異步更新
使用方式修改
import { nextTick } from 'vue'
nextTick(() => {
// ...
})
26,hook 生命周期事件
通過事件來監聽組件生命周期中的關鍵階段
語法
// V2的語法
<template>
<child-component @hook:updated="onUpdated">
</template>
// V3的語法
<template>
<child-component @vnode-updated="onUpdated">
</template>
// 駝峰寫法
<template>
<child-component @vnodeUpdated="onUpdated">
</template
如果看了覺得有幫助的,我是@鵬多多11997110103,歡迎 點贊 關注 評論;
END
PS:在本頁按F12,在console中輸入document.querySelectorAll('._2VdqdF')[0].click(),有驚喜哦
往期文章
- 助你上手Vue3全家桶之Vue-Router4教程
- 助你上手Vue3全家桶之VueX4教程
- 超詳細!Vuex手把手教程
- 使用nvm管理node.js版本以及更換npm淘寶鏡像源
- 超詳細!Vue-Router手把手教程
- vue中利用.env文件存儲全局環境變量,以及配置vue啟動和打包命令
- 微信小程序實現搜索關鍵詞高亮
個人主頁