淺析Vue3相關基礎知識點:setup()入口函數、ref()定義響應式數據、reactive()定義多個響應式數據-深層的、toRefs()轉換為每個屬性都是一個ref、computed()計算屬性、watch()監聽數據、watchEffect()監聽數據變化執行回調、生命周期對比、provide/inject跨層級組件通信


一、setup

  setup是組合Composition API中的入口函數,也是第一個要使用的函數。

1、setup只在初始化時執行一次,所有的Composition API函數都在此使用。

2、setup是在beforeCreate生命周期之前執行的(只執行一次)

 beforeCreate() { console.log('beforeCreate執行了'); }, setup() { console.log('setup執行了'); return {}; }, //setup執行了 //beforeCreate執行了

  由此可以推斷出setup執行的時候,組件對象還沒有創建,組件實例對象this還不可用,此時thisundefined, 不能通過this來訪問data/computed/methods/props

3、返回對象中的屬性會與data函數返回對象的屬性合並成為組件對象的屬性返回對象中的方法會與methods中的方法合並成功組件對象的方法,如果有重名,setup 優先

  因為在setupthis不可用,methods中可以訪問setup提供的屬性和方法, 但在setup方法中不能訪問datamethods里的內容,所以還是不建議混合使用

4、setup函數如果返回對象, 對象中的 屬性 或 方法 , 模板 中可以直接使用

//templete
<div>{{number}}</div>

//JS
setup() { const number = 18; return { number }; },

5、注意:setup不能是一個async函數: 因為返回值不再是return的對象,而是promise,模板中就不可以使用return中返回對象的數據了。

6、setup的參數(props,context)

(1)props: 是一個對象,里面有父級組件向子級組件傳遞的數據,並且是在子級組件中使用 props 接收到的所有的屬性

(2)context:上下文對象,可以通過es6語法解構 setup(props, {attrs, slots, emit})

  • attrs:獲取當前組件標簽上所有沒有通過props接收的屬性的對象, 相當於 this.$attrs
  • slots:包含所有傳入的插槽內容的對象,相當於 this.$slots
  • emit:用來分發自定義事件的函數,相當於 this.$emit

二、ref

1、作用:定義一個響應式的數據(一般用來定義一個基本類型的響應式數據UndefinedNullBooleanNumberString)

2、語法:const xxx = ref(initValue);

  注意script中操作數據需要使用xxx.value的形式,而模板中不需要添加.value

3、ref 用於定義響應式數據

// 用一個例子來演示:實現一個按鈕,點擊可以增加數字
<template>
  <div>{{count}}</div>
  <button @click='updateCount'>增加</button>
</template>

// 在Vue3中
 setup() { // ref用於定義一個響應式的數據,返回的是一個Ref對象,對象中有一個value屬性 //如果需要對數據進行操作,需要使用該Ref對象的value屬性
    const count = ref(0); function updateCount() { count.value++; } return { count, updateCount, }; },

4、ref 用於獲取 dom 節點:在Vue2中我們通過this.$refs來獲取dom節點,Vue3中我們通過ref來獲取節點

  首先需要在標簽上添加 ref='xxx',然后再setup中定義一個初始值為nullref類型,名字要和標簽的ref屬性一致

const xxx = ref(null)

  注意:一定要在setupreturn中返回,不然會報錯。

// 還是用一個例子來演示:讓輸入框自動獲取焦點
<template>
  <h2>App</h2>
  <input type="text" ref="inputRef">
</template>
<script lang="ts"> import { onMounted, ref } from 'vue'
/* ref獲取元素: 利用ref函數獲取組件中的標簽元素 功能需求: 讓輸入框自動獲取焦點 */ export default { setup() { const inputRef = ref<HTMLElement|null>(null) onMounted(() => { inputRef.value && inputRef.value.focus() }) return { inputRef } }, } </script>

三、reactive

1、語法:const proxy = reactive(obj)

2、作用:定義多個數據的響應式,接收一個普通對象然后返回該普通對象的響應式代理器對象(Proxy),響應式轉換是“深層的”:會影響對象內部所有嵌套的屬性,所有的數據都是響應式的。

<template>
  <h3>姓名:{{user.name}}</h3>
  <h3>wife:{{user.wife}}</h3>
  <button @click="updateUser">更新</button>
</template> setup() { const user = reactive({ name: '**', wife: { name: 'xioaohong', age: 18, books: [], }, }); const updateUser = () => { user.name = '小紅'; user.age += 2; user.wife.books[0] = '**'; }; return { user, updateUser, }; },

3、重點來了:ref 他強調的是一個數據的value的更改,reactive 強調的是定義的對象的某一個屬性的更改

四、toRefs

1、作用:把一個響應式對象轉換成普通對象,該普通對象的每個屬性都是一個 ref

2、應用:我們使用 reactive 創建的對象,如果想在模板中使用,就必須得使用 xxx.xxx 的形式;如果大量用到的話還是很麻煩的,但是使用 es6 解構以后,會失去響應式。

  那么toRefs的作用就體現在這,利用toRefs可以將一個響應式 reactive 對象的所有原始屬性轉換為響應式的ref屬性

<template>
  <div> name:{{name}} </div>
</template>

<script lang='ts'> import { defineComponent, reactive, toRefs } from 'vue'; export default defineComponent({ name: '', setup() { const state = reactive({ name: 'hzw', }); const state2 = toRefs(state); setInterval(() => { state.name += '==='; }, 1000); return { //通過toRefs返回的對象,解構出來的屬性也是響應式的
 ...state2, }; }, }); </script>

五、computed函數

1、與Vue2中的computed配置功能一致,返回的是一個ref類型的對象

2、計算屬性的函數中如果只傳入一個回調函數 表示的是get操作

3、計算屬性的函數中可以傳入一個對象,可以包含setget函數,進行讀取和修改的操作

const fullName2 = computed({ get() { return user.firstName + '_' + user.lastName; }, set(val: string) { const names = val.split('_'); user.firstName = names[0]; user.lastName = names[1]; }, }); return { user, fullName2, };

六、watch 函數

1、與Vue2中的watch配置功能一致:(1)參數1 - 要監聽的數據;(2)參數2 - 回調函數;(3)參數3 - 配置。

2、作用:監視指定的一個或多個響應式數據,一旦數據變化,就自動執行監視回調。

(1)默認初始時不執行回調,但可以通過配置 immediatetrue 來指定初始時立即執行第一次

(2)通過配置 deeptrue 來指定深度監視

3、監聽單一數據

import { ref, reactive, computed, watch } from 'vue'; setup(props) { // ref
    const age = ref(20); watch(() => age.value, (nv, ov) => { ... }); // reactive
   const product = reactive({ name: '飲料', count: 1 }); watch(() => product.count, (nv, ov) => { ... }); // props
   watch(() => props.msg, (nv, ov) => { ... }); // computed
   const userAge = computed(() => `今年${age.value}歲了!`); watch(() => userAge.value, (nv, ov) => { ... }); }

4、監聽對象

import { ref, reactive, watch } from 'vue'; setup(props) { // ref
    const user = ref({ name: 'zhang_san', age: 20 }); // 字面量引發的監聽觸發: user.value = { ... };
    watch(() => user.value, (nv, ov) => { ... }); // 如果使用 user.value.age = 30這種方式去修改user的age值; 將不會觸發上面的監聽,需要使用watch的第三個參數(深度監聽),且觸發監聽后的nv===ov true
    watch(() => user.value, (nv, ov) => { ... }, { deep: true }); // 如果我們只需要監聽name的值,那么
    watch(() => user.value.name, (nv, ov) => { ... }); // reactive
   const reactiveData = reactive({ user: { name: 'zhang_san', age: 20 } }); // 字面量引發的監聽觸發: reactiveData.user = { ... };
    watch(() => reactiveData.user, (nv, ov) => { ... }); // 如果使用 user.user.age = 30這種方式去修改user的age值,將不會觸發監聽,需要使用watch的第三個參數(深度監聽),且觸發監聽后的nv===ov true
    watch(() => reactiveData.user, (nv, ov) => { ... }, { deep: true }); // 如果我們只需要監聽name的值,那么
    watch(() => reactiveData.user.name, (nv, ov) => { ... }); }

5、監聽數組

import { ref, reactive, watch } from 'vue'; setup(props) { // ref
   const user = ref([ { name: 'zhang_san', age: 10 }, { name: 'li_si', age: 10 } ]); // 字面量引發的監聽觸發: user.value = [ ... ];
   watch(() => user.value, (nv, ov) => { ... }); // 如果使用數組的操作方法(如:push())或者user.value[0].age = 20這類操作去修改數組某項的屬性值,將不會觸發監聽,也需要使用深度監聽模式,且觸發監聽后的nv===ov true
  watch(() => user.value, (nv, ov) => { ... }, { deep: true }); // reactive
  const reactiveData = reactive({ user: [ { name: 'zhang_san', age: 10 }, { name: 'li_si', age: 10 } ] }); // 字面量引發的監聽觸發: user.user = [ ... ];
  watch(() => reactiveData.user, (nv, ov) => { ... }); // 如果使用數組的操作方法(如:push())或者user.value[0].age = 20這類操作去修改數組某項的屬性值,將不會觸發監聽,也需要使用深度監聽模式,且觸發監聽后的nv===ov true
  watch(() => reactiveData.user, (nv, ov) => { ... }, { deep: true }); }

6、監聽多個數據

import { ref, reactive, computed, watch } from 'vue'; setup(props) { const age = ref(20); const user = ref({ name: 'zhang_san', age: 20 }); watch([() => age.value, () => user.name], ([newAge, newName], [oldAge, oldName]) => { ... }); }

7、終止監聽

import { ref, watch } from 'vue'; const age = ref(20); // watch監聽會返回一個方法
const stop = watch(age, (nv, ov) => { ... }); // 當調用此方法后,該監聽就會被移除
stop();

七、watchEffect函數

1、作用:監視數據發生變化時執行回調,不用直接指定要監視的數據,回調函數中使用的哪些響應式數據就監視哪些響應式數據

2、默認初始時就會執行第一次,從而可以收集需要監視的數據。

import { watchEffect, ref } from 'vue'; const user = reactive({ firstName: '**', lastName: '**', }); const fullName4 = ref(''); watchEffect(() => { fullName4.value = user.firstName + '_' + user.lastName; }); return { user, fullName4, };

八、生命周期對比

  注意3.0中的生命周期鈎子要比2.X中相同生命周期的鈎子要快

setup() { onBeforeMount(() => { console.log('--onBeforeMount') }) onMounted(() => { console.log('--onMounted') }) ...... onBeforeUnmount(() => { console.log('--onBeforeUnmount') }) onUnmounted(() => { console.log('--onUnmounted') }) }

九、provide 與 inject

  作用:實現跨層級組件(祖孫)間通信

// 父組件
 setup() { const color = ref('red') provide('color', color) return { color } // 孫子組件
 setup() { const color = inject('color') return { color }

  這個 vue2 里也有,差不多一樣的用法。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM