Vue 3.x全面升級指南:Composition API深度探索

Vue 3.x 的全面升級引入了 Composition API胰柑,這是對 Vue 2.x 傳統(tǒng) Options API 的一個重大改進峦树,它提供了更加靈活和模塊化的代碼組織方式.

Composition API的核心概念和函數(shù)

setup()函數(shù):

Vue 3 中的核心入口辣辫,用于設(shè)置組件的狀態(tài)和邏輯,它在 beforeCreate 鉤子之后魁巩,create 鉤子之前執(zhí)行。代替了原本在 data姐浮、methods 等選項中定義的內(nèi)容谷遂。

import { ref, computed } from 'vue';

export default {
  setup() {
    // 響應(yīng)式數(shù)據(jù)
    const count = ref(0);

    // 計算屬性
    const doubleCount = computed(() => count.value * 2);

    // 方法
    function increment() {
      count.value++;
    }

    // 返回需要在模板中使用的數(shù)據(jù)和方法
    return {
      count,
      doubleCount,
      increment
    };
  }
};

ref 和 reactive:

用于創(chuàng)建響應(yīng)式數(shù)據(jù),ref用于創(chuàng)建基本類型的響應(yīng)式數(shù)據(jù)卖鲤,reactive 用于對象和數(shù)組的響應(yīng)式代理肾扰。

import { ref, reactive } from 'vue';

export default {
  setup() {
    // 使用ref創(chuàng)建響應(yīng)式基本類型
    const count = ref(0);

    // 使用reactive創(chuàng)建響應(yīng)式對象
    const user = reactive({
      name: 'Alice',
      age: 30
    });

    // 修改響應(yīng)式數(shù)據(jù)
    count.value++;
    user.age++;

    return { count, user };
  }
};

計算屬性與偵聽器:

computed 用于創(chuàng)建計算屬性,只有當(dāng)依賴發(fā)生變化時才會重新計算蛋逾。

import { ref, computed } from 'vue';

export default {
  setup() {
    const firstName = ref('John');
    const lastName = ref('Doe');

    // 計算全名
    const fullName = computed(() => `${firstName.value} ${lastName.value}`);

    return { firstName, lastName, fullName };
  }
};

watch 用于觀察響應(yīng)式數(shù)據(jù)的變化集晚,并在變化時執(zhí)行回調(diào)。

import { ref, watch } from 'vue';

export default {
  setup() {
    const count = ref(0);

    // 觀察count變化
    watch(count, (newVal, oldVal) => {
      console.log(`count changed from ${oldVal} to ${newVal}`);
    });

    function increment() {
      count.value++;
    }

    return { count, increment };
  }
};

組合函數(shù)

Composition API鼓勵創(chuàng)建可復(fù)用的組合函數(shù)区匣。

// useCounter.js
export function useCounter(initialValue = 0) {
  const count = ref(initialValue);
  function increment() {
    count.value++;
  }
  return { count, increment };
}

// 在組件中使用
import { useCounter } from './useCounter';

export default {
  setup() {
    const { count, increment } = useCounter(10);
    return { count, increment };
  }
};

生命周期鉤子:

Vue 3 中的生命周期鉤子不再直接在 setup() 內(nèi)部使用偷拔,而是通過 onBeforeMount、onMounted 等新的生命周期鉤子函數(shù)亏钩。

1. onBeforeMount: 此鉤子在組件掛載到DOM之前被調(diào)用莲绰。這類似于Vue 2.x中的 beforeMount 生命周期鉤子。

   import { onBeforeMount } from 'vue';
   
   export default {
     setup() {
       onBeforeMount(() => {
         console.log('組件即將掛載');
       });
     }
   };

2. onMounted: 當(dāng)組件被掛載到DOM上后立即調(diào)用姑丑。相當(dāng)于Vue 2.x的 mounted蛤签。

   import { onMounted } from 'vue';
   
   export default {
     setup() {
       onMounted(() => {
         console.log('組件已掛載');
       });
     }
   };

3. onBeforeUpdate: 在組件數(shù)據(jù)變化導(dǎo)致的更新之前調(diào)用,但還未開始DOM更新栅哀。類似于Vue 2.x的 beforeUpdate震肮。

   import { onBeforeUpdate } from 'vue';
   
   export default {
     setup() {
       let previousData;
       onBeforeUpdate(() => {
         console.log('數(shù)據(jù)更新前:', previousData);
       });
       
       return { data };
     }
   };

4. onUpdated: 組件數(shù)據(jù)變化導(dǎo)致的DOM更新完成后調(diào)用。相當(dāng)于Vue 2.x的 updated留拾。

   import { onUpdated } from 'vue';
   
   export default {
     setup() {
       onUpdated(() => {
         console.log('組件更新完成');
       });
     }
   };

5. onBeforeUnmount: 組件卸載之前調(diào)用戳晌。類似于Vue 2.x的 beforeDestroy。

   import { onBeforeUnmount } from 'vue';
   
   export default {
     setup() {
       onBeforeUnmount(() => {
         console.log('組件即將卸載');
       });
     }
   };

6. onUnmounted: 組件已經(jīng)被卸載后調(diào)用间驮。相當(dāng)于Vue 2.x的 destroyed躬厌。

   import { onUnmounted } from 'vue';
   
   export default {
     setup() {
       onUnmounted(() => {
         console.log('組件已卸載');
       });
     }
   };

7. onActivated: 僅在使用 <keep-alive> 包裹的組件激活時調(diào)用。

   import { onActivated } from 'vue';
   
   export default {
     setup() {
       onActivated(() => {
         console.log('組件被激活');
       });
     }
   };

8. onDeactivated: 僅在使用 <keep-alive> 包裹的組件停用時調(diào)用竞帽。

   import { onDeactivated } from 'vue';
   
   export default {
     setup() {
       onDeactivated(() => {
         console.log('組件被停用');
       });
     }
   };

Composition API編寫組件

  • 創(chuàng)建響應(yīng)式數(shù)據(jù):使用 ref 和 reactive 創(chuàng)建響應(yīng)式變量扛施。
  • 計算屬性:使用 computed 函數(shù)創(chuàng)建計算屬性。
  • 響應(yīng)式函數(shù):使用 toRefs() 和 toRef() 轉(zhuǎn)換對象屬性為響應(yīng)式屹篓。
  • 監(jiān)聽器:使用 watch 或 watchEffect 監(jiān)聽數(shù)據(jù)變化疙渣。
import { ref, reactive, computed, toRefs, watch } from 'vue';
import axios from 'axios';

export default {
  setup() {
    // 創(chuàng)建響應(yīng)式數(shù)據(jù)
    const state = reactive({
      cityInput: '',
      city: '',
      weather: null
    });

    // 計算屬性,直接返回輸入的城市名稱
    const currentCity = computed(() => state.cityInput);

    // 將state對象的屬性轉(zhuǎn)化為響應(yīng)式引用
    const { cityInput } = toRefs(state);

    // 響應(yīng)式函數(shù)堆巧,用于處理API請求
    const fetchWeather = async () => {
      if (!cityInput.value.trim()) return;

      try {
        const response = await axios.get(`https://api.weatherapi.com/v1/current.json?key=YOUR_API_KEY&q=${cityInput.value}`);
        state.city = response.data.location.name;
        state.weather = { temp: response.data.current.temp_c };
      } catch (error) {
        console.error('獲取天氣信息失敗', error);
      }
    };

    // 監(jiān)聽器妄荔,監(jiān)聽城市輸入變化泼菌,清空天氣信息
    watch(cityInput, () => {
      state.weather = null;
    });

    // 返回暴露給模板的變量和方法
    return {
      cityInput,
      currentCity,
      fetchWeather
    };
  }
};
  • 創(chuàng)建響應(yīng)式數(shù)據(jù):使用reactive創(chuàng)建了一個包含cityInputcityweather的響應(yīng)式對象啦租。ref也可以用于基本類型的響應(yīng)式數(shù)據(jù)哗伯,但在這個場景下,reactive更適合管理多個狀態(tài)篷角。

  • 計算屬性: currentCity計算屬性直接返回state.cityInput的值焊刹,雖然在這個例子中直接使用v-model="cityInput"可能更直觀,但展示了如何定義計算屬性恳蹲。

  • 響應(yīng)式函數(shù): 使用toRefsstate對象的屬性轉(zhuǎn)化為獨立的響應(yīng)式引用虐块,便于在模板中直接綁定。這里主要展示了響應(yīng)式數(shù)據(jù)的使用嘉蕾,而不是轉(zhuǎn)換函數(shù)本身贺奠,因為直接使用解構(gòu)賦值(如const { cityInput } = state;)在模板中已經(jīng)足夠。

  • 監(jiān)聽器: 使用watch監(jiān)聽cityInput的變化错忱,每次輸入變化時清除weather狀態(tài)儡率,以便于下次查詢。

從Options API遷移到Composition API

組件結(jié)構(gòu)

將狀態(tài)航背、方法和邏輯分離到單獨的函數(shù)中喉悴。在Options API中,我們通常在組件選項中定義data玖媚、methods箕肃、computed等。而在Composition API中今魔,這些邏輯被分離到單獨的函數(shù)中勺像。例如:

Options API:

export default {
  data() {
    return {
      message: 'Hello, Vue!'
    };
  },
  methods: {
    greet() {
      console.log(this.message);
    }
  },
  computed: {
    reversedMessage() {
      return this.message.split('').reverse().join('');
    }
  }
};

Composition API:

import { ref, computed } from 'vue';

export default {
  setup() {
    const message = ref('Hello, Vue!');
    
    function greet() {
      console.log(message.value);
    }
    
    const reversedMessage = computed(() => message.value.split('').reverse().join(''));

    return {
      message,
      greet,
      reversedMessage
    };
  }
};

依賴注入

使用 provide 和 inject。在Options API中错森,我們使用provide和inject來傳遞數(shù)據(jù)吟宦。在Composition API中,這個過程保持不變:

Options API:

// 父組件
export default {
  provide() {
    return {
      parentValue: '父組件的值'
    };
  }
};

// 子組件
export default {
  inject: ['parentValue'],
  mounted() {
    console.log(this.parentValue); // 輸出 "父組件的值"
  }
};

Composition API:

// 父組件
export default {
  setup() {
    provide('parentValue', '父組件的值');
  }
};

// 子組件
export default {
  setup(_, { inject }) {
    const parentValue = inject('parentValue');
    onMounted(() => {
      console.log(parentValue); // 輸出 "父組件的值"
    });
  }
};

模板重構(gòu)

將綁定的屬性和方法從 this 轉(zhuǎn)換為直接引用涩维。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末殃姓,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子瓦阐,更是在濱河造成了極大的恐慌蜗侈,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件睡蟋,死亡現(xiàn)場離奇詭異踏幻,居然都是意外死亡,警方通過查閱死者的電腦和手機戳杀,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進店門该面,熙熙樓的掌柜王于貴愁眉苦臉地迎上來夭苗,“玉大人,你說我怎么就攤上這事隔缀√庠欤” “怎么了?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵猾瘸,是天一觀的道長晌梨。 經(jīng)常有香客問我,道長须妻,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任泛领,我火速辦了婚禮荒吏,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘渊鞋。我一直安慰自己绰更,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布锡宋。 她就那樣靜靜地躺著儡湾,像睡著了一般。 火紅的嫁衣襯著肌膚如雪执俩。 梳的紋絲不亂的頭發(fā)上徐钠,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天,我揣著相機與錄音役首,去河邊找鬼尝丐。 笑死,一個胖子當(dāng)著我的面吹牛衡奥,可吹牛的內(nèi)容都是我干的爹袁。 我是一名探鬼主播,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼矮固,長吁一口氣:“原來是場噩夢啊……” “哼失息!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起档址,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤盹兢,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后辰晕,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蛤迎,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年含友,在試婚紗的時候發(fā)現(xiàn)自己被綠了替裆。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片校辩。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖辆童,靈堂內(nèi)的尸體忽然破棺而出宜咒,到底是詐尸還是另有隱情,我是刑警寧澤把鉴,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布故黑,位于F島的核電站,受9級特大地震影響庭砍,放射性物質(zhì)發(fā)生泄漏场晶。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一怠缸、第九天 我趴在偏房一處隱蔽的房頂上張望诗轻。 院中可真熱鬧,春花似錦揭北、人聲如沸扳炬。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽恨樟。三九已至,卻和暖如春疚俱,著一層夾襖步出監(jiān)牢的瞬間劝术,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工计螺, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留夯尽,地道東北人。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓登馒,卻偏偏與公主長得像匙握,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子陈轿,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,916評論 2 344

推薦閱讀更多精彩內(nèi)容