首頁>技術>

前言

Composition API 將是 Vue 3 的核心功能,它具有許多更改和效能改進。我們也可以在 Vue 2 中通過 npm 外掛@vue/composition-api 使用它。本文重點將帶你了解:

@vue/composition-api常見 api 使用vue3 程式碼邏輯提取和複用如何使用provide+inject替代vuex方案vue2 使用 composition-api

主檔案 main.ts 或者 app.vue 新增

import Vue from 'vue'import VueCompositionAPI from '@vue/composition-api'Vue.use(VueCompositionAPI)

Composition API 不再傳入 data、mounted 等引數, 通過引入的 ref、onMounted等方法實現資料的雙向繫結、生命週期函式的執行。

核心語法

reactive:接收一個普通物件然後返回該普通物件的響應式代理。

ref:接受一個引數值並返回一個響應式且可改變的 ref 物件。ref 物件擁有一個指向內部值的單一屬性 .value。

computed:傳入一個 getter 函式,返回一個預設不可手動修改的 ref 物件。

readonly:傳入一個物件(響應式或普通)或 ref,返回一個原始物件的只讀代理。一個只讀的代理是“深層的”,物件內部任何巢狀的屬性也都是隻讀的。

watchEffect:立即執行傳入的一個函式,並響應式追蹤其依賴,並在其依賴變更時重新執行該函式。可顯式的呼叫返回值以停止偵聽。

watch:全等效於 2.x this.\\$watch (以及 watch 中相應的選項)。

setup 函式

現在要介紹的第一個 API 就是 setup 函式。setup 函式是一個新的元件選項。作為在元件內使用 Composition API 的入口點。先看個簡單 demo

<template>  <button @click="increase">count is: {{ count }}</button></template><script>  export default {    setup() {      let count = 0      const increase = () => count++      return { count, increase }    },  }</script>

1、呼叫時機

建立元件例項,然後初始化 props ,緊接著就呼叫 setup 函式。從 vue2 生命週期鉤子的視角來看,它會在 beforeCreate 鉤子之後,created 之前被呼叫。

2、模板中使用

如果 setup 返回一個物件,則物件的屬性將會被合併到元件模板的渲染上下文。

3、渲染函式 / JSX 中使用

setup 也可以返回一個函式,函式中也能使用當前 setup 函式作用域中的響應式資料:

import { h, ref, reactive } from '@vue/composition-api'export default {  setup() {    const count = ref(0)    const object = reactive({ foo: 'bar' })    return () => h('div', [count.value, object.foo])  },}

4、兩個引數props(注意 props 物件是響應式的),context(上下文物件,從原來 2.x 中 this 選擇性地暴露了一些 property。)

const MyComponent = {  setup(props, context) {    let {      attrs,      emit,      isServer,      listeners,      parent,      refs,      root,      slots,      ssrContext,    } = context  },}
ref & reactive

在 App.vue 中,點選事件綁定了 increase,然後修改了 count, 但是頁面並沒有發生改變,這是因為 setup 函式返回的物件中 count 不是響應式資料, 那麼如何建立響應式資料呢?此時就要掌握響應式系統 API,我們可以使用 ref 和 reactive 建立。

<template>  <button @click="increase">    count is: {{ count }}, state.count is {{ state.count }}  </button></template><script>  import { ref, reactive } from 'vue'  export default {    setup() {      let count = ref(0) // { value: 0 }      let state = reactive({ number: 0 })      const increase = () => {        count.value++        state.count++      }      return { count, state, increase }    },  }</script>

接受一個引數值並返回一個響應式且可改變的 ref 物件。ref 物件擁有一個指向內部值的單一屬性 .value。

當 ref 作為渲染上下文的屬性返回(即在 setup() 返回的物件中)並在模板中使用時, 它會自動解套,無需在模板內額外書寫 .value

Vue 本身已經有 "ref" 的概念了。但只是為了在模板中獲取 DOM 元素或元件例項 (“模板引用”)。新的 ref 系統同時用於邏輯狀態和模板引用。

reactive 接收一個普通物件然後返回該普通物件的響應式代理。

響應式轉換是“深層的”:會影響物件內部所有巢狀的屬性。基於 ES2015 的 Proxy 實現,返回的代理物件不等於原始物件。建議僅使用代理物件而避免依賴原始物件。

不要解構返回的代理物件,那樣會使其失去響應性:

<template>  <button @click="increase">count is: {{ count }}</button></template><script>  import { ref, reactive } from '@vue/composition-api'  export default {    setup() {      let state = reactive({ count: 0 })      const increase = () => state.count++      return { ...state, increase } // 展開state屬性將失去響應式    },  }</script>
toRef 和 toRefs

那如果我們真的想展開 state 的屬性,在模板使用 count 而不是 state.count 的寫法那怎麼辦呢?我們可以使用 toRef 和 toRefs 這兩個 API,進行轉換成 ref 物件,之前已經介紹了 ref 物件是可以直接在模板中使用的。

toRef 可以用來為一個 reactive 物件的屬性建立一個 ref。這個 ref 可以被傳遞並且能夠保持響應性。

<template>  <button @click="increase">    count is: {{ count }},count2 is: {{ count2 }}  </button></template><script>  import { ref, reactive, toRef, toRefs } from '@vue/composition-api'  export default {    setup() {      let state = reactive({ count: 0 })      let countRef = toRef(state, 'count')      let state2 = reactive({ count2: 0 })      const increase = () => state.count++      let stateAsRefs = toRefs(state2)      return { count: countRef, increase, ...stateAsRefs }    },  }</script>

把一個響應式物件轉換成普通物件,該普通物件的每個 property 都是一個 ref ,和響應式物件 property 一一對應。

computed & watch
const countDouble = computed(() => count.value * 2)watch(  () => state.count,  (count, prevCount) => {    /* ... */  })
程式碼邏輯提取和複用

Composition API 的第一個明顯優勢是很容易提取邏輯。解決了

邏輯提取
export const useCount = (number) => {  const count = ref(0)  const increase = () => {    count.value += 1  }  const reset = () => {    count.value = 0  }  onMounted(() => {    count.value = number  })  return {    count,    increase,    reset,  }}
程式碼複用
// 另外一個檔案使用:const { count, increase } = useCount(1)console.log(count) //輸出1increase()console.log(count) //輸出2reset()console.log(count) //輸出0

有效的解決了 mixins 複用命名衝突,難以識別命名來自哪個 mixin 檔案的問題。

替代 vuex 狀態管理

狀態 store 可以放在一個單一的檔案或者目錄裡,比如設定一個全域性元件可以只用的配置 config

//context/config.tsimport { provide, inject, ref, onMounted, readonly } from '@vue/composition-api'const configSymbol: symbol = Symbol()export const useProvider = {  setup() {    let config = ref(null)    const configServer = async () => {      // await 一些非同步操作,比如api等      config.value = { name: '名字' }    }    onMounted(async () => {      await configServer()    })    provide(configSymbol, {      //匯出只讀的config只有函式內部可以修改狀態      config: readonly(config),    })  },}export const useInject = () => {  return inject(configSymbol)}

在最頂層的元件(例如 main.ts)上注入,config 就可以在所有的元件中使用

import { defineComponent } from '@vue/composition-api'import { useProvider } from './context/config'export default defineComponent({  setup() {    useProvider()  },})

業務邏輯頁面使用 config

import { useInject } from './context/config'const Components = {  setup() {    const { config } = useInject()    console.log(config.value.name) //輸出“名字”    return {      config,    }  },}

91
最新評論
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • iframe接班人微前端框架qiankun在中後臺系統實踐