1. 程式人生 > 實用技巧 >Vue3 中令人興奮的新功能

Vue3 中令人興奮的新功能

元件 API(Composition API)

元件 API 是 Vue 的下一個主要版本中最常用的討論和特色語法。這是一種全新的邏輯重用和程式碼組織方法。

當前,我們使用所謂的 Options API 構建元件。為了向 Vue 元件新增邏輯,我們填充(可選)屬性,例如data、methods、computed等。這種方法的最大缺點是其本身並不是有效的JavaScript程式碼。你需要確切地知道模板中可以訪問哪些屬性以及this關鍵字的行為。在後臺,Vue 編譯器需要將此屬性轉換為工作程式碼。因此我們無法從自動建議或型別檢查中受益。

元件 API 旨在通過將元件屬性中當前可用的機制公開為JavaScript函式來解決這個問題。 Vue 核心團隊將元件 API 描述為“一組基於函式的附加 API,可以靈活地組合元件邏輯。”

用元件 API 編寫的程式碼更具有可讀性,並且其背後沒有任何魔力,因此更易於閱讀和學習。

讓我們通過一個用了新的元件 API 的元件的簡單示例,來了解其工作原理。

<template>
  <button @click="increment">
    Count is: {{ count }}, double is {{ double }}, click to increment.
  </button>
</template>

<script>
import { ref, computed, onMounted } from 'vue'

export default {
  setup() {
    const
count = ref(0) const double = computed(() => count.value * 2) function increment() { count.value++ } onMounted(() => console.log('component mounted!')) return { count, double, increment } } } </script>

現在,讓我們把程式碼分解為幾部分,來了解發生了些什麼:

import{ ref, computed, onMounted }from'vue'

正如我之前提到的,元件 API 將元件屬性公開為函式,因此第一步是匯入所需的函式。在例子中,需要使用ref建立響應性引用,用computed建立計算屬性,並用onMounted訪問安裝的生命週期 hook。

現在你可能很想知道這神祕的setup方法到底是什麼?

export default {
  setup() {

簡而言之,它只是一個將屬性和函式返回到模板的函式而已。我們在這裡宣告所有響應性屬性、計算屬性、觀察者和生命週期 hook,然後將它們返回,以便可以在模板中使用它們。

我們不從setup函式返回的內容在模板中將會不可用。

constcount = ref(0)

根據上面的內容,我們聲明瞭帶有ref函式的名為count的響應屬性。它可以包裝任何原語或物件並返回其響應性引用。傳遞的元素的值將會保留在所建立引用的value屬性中。例如,如果你想訪問count引用的值,則需要明確要求count.value。

const double = computed(() => count.value * 2)

function increment() {
  count.value++
}

這正是我們在宣告計算屬性double和increment函式時所要做的。

onMounted(()=>console.log('component mounted!'))

使用onMountedhook,我們會在安裝元件時記錄一些訊息,只是向你展示可以做到!

return {
  count,
  double,
  increment
}

最後,我們將使用increment方法返回count和double屬性,以使它們在模板中可用。

<template>
  <button @click="increment">
    Count is: {{ count }}, double is {{ double }}. Click to increment.
  </button>
</template>

瞧!現在我們可以訪問模板中setup方法返回的屬性和函式,就像通過舊的 Options API 宣告它們一樣。

這是一個簡單的例子,也可以通過 Options API 輕鬆實現。新的元件 API 的真正好處不僅在於能以不同的方式進行編碼,在對我們的程式碼和邏輯進行重用時,這些好處也能顯示出來。

用元件 API 進行程式碼重用

新的元件 API 具有更多優點。考慮一下程式碼重用。目前如果我們要在其他元件之間共享一些程式碼,則有兩個可用的選擇:mixins 和作用域插槽( scoped slots)。但是兩者都有缺點。

假設我們要提取counter中的功能並在其他元件中重用。在下面,你可以看到如何將其與可用的 API 和新的元件 API 結合使用:

讓我們從 mixins 開始:

import CounterMixin from './mixins/counter'

export default {
  mixins: [CounterMixin]
}

mixins 的最大缺點在於我們對它實際上新增到元件中的行為一無所知。這不僅使程式碼變得難以理解,而且還可能導致名稱與現有屬性和函式發生衝突。

下面是作用域插槽:

<template>
  <Counter v-slot="{ count, increment }">
     {{ count }}
    <button @click="increment">Increment</button> 
  </Counter> 
</template>

通過使用作用域插槽,我們確切地知道可以通過v-slot屬性訪問了哪些屬性,因此程式碼更容易理解。這種方法的缺點是我們只能在模板中訪問它,並且只能在Counter元件作用域內使用。

現在該用元件 API 了:

function useCounter() {
  const count = ref(0)
  function increment () { count.value++ }

  return {
    count,
    incrememt
  }
}

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

是不是更優雅?我們不受模板和元件作用域的限制,並且能夠確切地知道可以從 counter 訪問哪些屬性。另外我們可以受益於編輯器中可用的程式碼補全功能,因為useCounter只是一個返回某些屬性的函式,因此編輯器可以幫助我們進行型別檢查和建議。

這也是使用第三方庫的更優雅的方式。例如,如果我們想使用 Vuex,則可以顯式地使用useStore函式,而不是汙染 Vue 原型(this.$store)。這種方法也消除了 Vue 外掛的幕後魔力。

const{ commit, dispatch } = useStore()

如果你想了解有關元件 API 及其使用案例的更多資訊,我強烈建議你閱讀 Vue 團隊的這篇文章,其中解釋了新 API 背後的原因,並提出了最好的用例建議。還有great repository,其中包含來自 Vue 核心團隊的 Thorsten Lünborg 使用的元件 API 的例子。

全域性掛載/配置 API 更改

我們可以在例項化和配置程式的方式中找到另一個重大變化。讓我們看看它現在是如何工作的:

import Vue from 'vue'
import App from './App.vue'

Vue.config.ignoredElements = [/^app-/]
Vue.use(/* ... */)
Vue.mixin(/* ... */)
Vue.component(/* ... */)
Vue.directive(/* ... */)

new Vue({
  render: h => h(App)
}).$mount('#app')

當前,我們正在用全域性Vue物件提供所有配置並建立新的 Vue 例項。對Vue物件所做的任何更改都會影響每個 Vue 例項和元件。

現在,讓我們看看它如何在 Vue 3 中執行:

import { createApp } from 'vue'
import App from './App.vue'

const app = createApp(App)

app.config.ignoredElements = [/^app-/]
app.use(/* ... */)
app.mixin(/* ... */)
app.component(/* ... */)
app.directive(/* ... */)

app.mount('#app')

你可能已經注意到,每個配置都限於使用createApp定義的某個 Vue 程式。

它可以使你的程式碼更易於理解,並且不易出現由第三方外掛引發的意外問題。目前,如果某些第三方解決方案正在修改 Vue 物件,那麼它可能會以意想不到的方式(尤其是全域性混合)影響你的程式,而 Vue 3 則沒有這個問題。

目前,此 API 的更改正在這個 RFC中進行討論,這意味著將來可能會有所更改。

片段(Fragments)

我們可以在 Vue 3 中期待的另一個激動人心的附加功能是片段。

你可能會問什麼片段?好吧,如果你建立了一個 Vue 元件,那麼它只能有一個根節點。

這意味著無法建立這樣的元件:

<template>
  <div>Hello</div>
  <div>World</div>
</template>

原因是代表任何 Vue 元件的 Vue 例項都需要繫結到單個 DOM 元素中。建立具有多個 DOM 節點的元件的唯一方法是建立一個沒有基礎 Vue 例項的功能元件。

事實證明,react社群也有同樣的問題。他們提出的解決方案是一個名為 Fragment 的虛擬元素。看上去是這樣的;

class Columns extends react.Component {
  render() {
    return (
      <React.Fragment>
        <td>Hello</td>
        <td>World</td>
      </React.Fragment>
    );
  }
}

儘管 Fragment 看起來像是普通的 DOM 元素,但它是虛擬的,根本不會在 DOM 樹中渲染。這樣我們就可以將元件功能繫結到單個元素中,而無需建立冗餘的 DOM 節點。

現在你可以在帶有vue-fragments庫的 Vue 2 中使用片段,而在 Vue 3 中你可以直接使用它!

Suspense

將被用在 Vue 3 中的另一個從 React 學來的功能是 Suspense 元件。

Suspense 能夠暫停你的元件渲染,並渲染後備元件,直到條件滿足為止。在 Vue London 期間,尤雨溪簡短地談到了這個主題,並向我們展示了可以期望的 API。事實證明,Suspense 只是帶有插槽的元件:

<Suspense>
  <template >
    <Suspended-component />
  </template>
  <template #fallback>
    Loading...
  </template>
</Suspense>

直到Suspended-component完全渲染前將會顯示後備內容。掛起可以等待,直到該元件被下載(如果該元件是非同步元件的話),或者在setup函式中執行一些非同步操作。

Multiple v-models

V-model 是一種指令,可用於在給定元件上實現雙向繫結。我們可以傳遞響應性屬性,並從元件內部對其進行修改。

我們可以從表單元素上很好的瞭解v-model:

<inputv-bind="property />

但是你知道可以對每個元件都使用v-model嗎?在內部,v-model只是傳遞value屬性和偵聽input事件的捷徑。把上面的例子重寫為以下語法,將具有完全相同的效果:

<input 
  v-bind:value="property"
  v-on:input="property = $event.target.value"
/>

我們甚至可以用元件model屬性來更改預設屬性和事件的名稱:

model: {
  prop: 'checked',
  event: 'change'
}

如你所見,如果我們想要在元件中進行雙向繫結,v-model指令可能是一個非常有用的語法。不幸的是,每個元件只能有一個v-model。

幸運的是,這在 Vue 3 中不會有問題!你將能夠給v-model屬性名,並根據需要擁有儘可能多的屬性名。在下面的例子中,你可以在表單元件中找到兩個v-model:

<InviteeForm
  v-model:name="inviteeName"
  v-model:email="inviteeEmail"
/>

目前,此 API 的更改已在這個 RFC中進行討論,這意味著將來可能會有更改。

Portals

Portals 是特殊的元件,用來在當前元件之外渲染某些內容。它也是在 React 中實現的功能之一。這就是 React 文件關於 Portals 的內容:

Portals 提供了一種獨特的方法來將子級渲染到父元件的 DOM 層次結構之外的 DOM 節點中。

這種處理模式,是彈出式視窗以及通常顯示在頁面頂部的元件所使用的一種非常好的方法。通過使用 Portals,你可以確保沒有任何主機元件css規則會影響你要顯示的元件,並且可以避免用z-index進行的黑客攻擊。

對於每個 Portal,我們需要為其指定目標位置,在該目標位置將渲染 Portals 內容。在下面,你可以從portal-vue庫中看到實現,該庫將此功能新增到了 Vue 2:

<portal to="destination">
  <p>This slot content will be rendered wherever thportal-target with name 'destination'
    is  located.</p>
</portal>

<portal-target name="destination">
  <!--
  This component can be located anywhere in your App.
  The slot content of the above portal component wilbe rendered here.
  -->
</portal-target>

Vue 3 對 Portals 提供開箱即用的支援!

資源搜尋網站大全 http://www.szhdn.com 廣州VI設計公司https://www.houdianzi.com

新的自定義指令 API

自定義指令 API 在 Vue 3 中將略有變化,以便更好地與元件生命週期保持一致。這項改進應使 API 更加直觀,從而使新手更容易理解和學習 API。

這是當前的自定義指令 API:

const MyDirective = {
  bind(el, binding, vnode, prevVnode) {},
  inserted() {},
  update() {},
  componentUpdated() {},
  unbind() {}
}

這是在 Vue 3 中的樣子。

const MyDirective = {
  beforeMount(el, binding, vnode, prevVnode) {},
  mounted() {},
  beforeUpdate() {},
  updated() {},
  beforeUnmount() {}, // new
  unmounted() {}
}

即使這是一項重大改進,也應很容易被 Vue 相容版本涵蓋到。

在此 RFC中討論了這個 API 的更改,這意味著將來可能會改進。