Vue 3尚未正式發布,但是維護者已經發布了Beta版本,供我們的參與者嘗試并提供反饋,
如果你想知道Vue 3的主要功能和主要變化是什么,那么我將在這篇文章中重點介紹一下,告訴你使用Vue 3 beta 9創建一個簡單的應用程式,
我將介紹盡可能多的新內容,包括fragments,teleport,Composition API以及其他一些晦澀的更改,我將盡力解釋該功能或更改的原理,
Vue3相關文章:
- Vue3 Composition API如何替換Vue Mixins
- Vue3 Composition API中的提取和重用邏輯
- 如何在Vue2與Vue3中構建相同的組件
- Vue3中的Vue Router初探
我們將建立什么
我們將構建一個帶有模式視窗功能的簡單應用,我之所以選擇它,是因為它可以方便地展示Vue 3的許多變化,
這是該應用在打開和關閉狀態下的外觀,因此你可以在腦海中描繪出我們正在做什么:
Vue 3安裝和setup
與其直接安裝Vue 3,不如克隆一個專案 vue-next-webpack-preview,這將為我們提供一個包括Vue 3在內的最小的Webpack設定,
$ git clone https://github.com/vuejs/vue-next-webpack-preview.git vue3-experiment
$ cd vue3-experiment
$ npm i
復制代碼
一旦克隆好了,安裝好了NPM模塊,我們需要做的就是洗掉樣板檔案,然后創建一個新的 main.js 檔案,這樣我們就可以從頭開始創建我們的Vue 3 app了,
$ rm -rf src/*
$ touch src/main.js
復制代碼
現在,我們將運行開發服務器:
$ npm run dev
復制代碼
創建一個新的Vue 3 app
我們啟動一個新的Vue應用程式的方式改變了,我們現在需要匯入新的 createApp 方法,而不是使用新的 Vue(),
我們呼叫這個方法,傳遞我們的Vue實體定義物件,并將回傳物件分配給一個變數 app,
接下來,我們將在 app 上呼叫 mount 方法,并傳遞一個CSS選擇器來指示我們的mount元素,就像在Vue 2中使用 $mount 實體方法一樣,
// src/main.js
import { createApp } from "vue";
const app = createApp({
// 根實體定義
});
app.mount("#app");

變化的原因
與舊的API一樣,我們添加的任何全域配置(plugins,mixins,原型屬性等)都將永久更改全域狀態,例如:
// src/main.js
// 影響兩個實體
Vue.mixin({ ... })
const app1 = new Vue({ el: '#app-1' })
const app2 = new Vue({ el: '#app-2' })
復制代碼
在單元測驗中,這確實是一個問題,因為要確保將每個測驗都與上一個測驗隔離是很棘手的,
在新的API下,呼叫 createApp 將回傳一個新的app實體,該實體不會被應用于其他實體的任何全域配置污染,
了解更多:Global API change RFC,
添加state屬性
我們的模態視窗可以處于兩種狀態之一——打開或關閉,讓我們用一個布爾狀態屬性 modalOpen 來管理它,我們將給它一個初始值 false,
在Vue 2下,我們可以通過在我們的應用實體上創建一個 data 屬性并將一個物件分配給該物件來宣告 modalOpen 屬性,例如:
// src/main.js
const app = createApp({
data: {
modalOpen: false
}
});
復制代碼
不再允許這樣做,相反,必須為資料分配一個回傳狀態物件的工廠函式,
// src/main.js
const app = createApp({
data: () => ({
modalOpen: false
})
});
復制代碼
變化的原因
使用物件而不是工廠函式來存盤資料的優點是,首先,它在語法上更簡單;其次,你可以在多個根實體之間共享頂級狀態,例如:
// src/main.js
const state = {
sharedVal: 0
};
const app1 = new Vue({ state });
const app2 = new Vue({ state });
// 影響兩個實體
app1._data.sharedVal = 1;
復制代碼
這種用例很少,可以使用,因為有兩種型別的宣告是不適合初學者的,所以決定洗掉這個特性,
了解更多:Data object declaration removed RFC
在繼續之前,我們還添加一個方法來切換 modalOpen 值,這與Vue 2沒什么不同,
// src/main.js
const app = createApp({
data: () => ({
modalOpen: true
}),
methods: {
toggleModalState() {
this.modalOpen = !this.modalOpen;
}
}
});
復制代碼
使用一個根組件
如果你現在進入瀏覽器并檢查控制臺,則會看到警告“Component is missing render function”,因為我們尚未為根實體定義模板,
Vue 2的最佳實踐是為根實體創建一個最小的模板,并創建一個app組件,其中將宣告主app標記,
讓我們在這里也這樣做,
$ touch src/App.vue
復制代碼
現在我們可以獲取根實體來渲染該組件,區別在于,對于Vue 2,我們通常會使用render函式來執行此操作:
// src/main.js
import App from "./App.vue";
const app = createApp({
...
render: h => h(App)
});
app.mount("#app");
復制代碼
我們仍然可以做到這一點,但是Vue 3有一個更簡單的方法——使 App 成為根組件,為此,我們可以洗掉根實體定義,而是傳遞 App 組件,
// src/main.js
import App from "./App.vue";
const app = createApp(App);
app.mount("#app");
復制代碼
這意味著 App 組件不僅由根實體渲染,而且是根實體,
在此程序中,我們通過洗掉 app 變數來簡化語法:
// src/main.js
createApp(App).mount("#app");
復制代碼
現在移至根組件,讓我們向該組件重新添加狀態和方法:
// src/App.vue
<script>
export default {
data: () => ({
modalOpen: true
}),
methods: {
toggleModalState() {
this.modalOpen = !this.modalOpen;
}
}
};
</script>
復制代碼
我們還為模態功能創建一個新組件:
$ touch src/Modal.vue
復制代碼
現在,我們將提供一個最小的模板,其中包括內容插槽,這確保了我們的模態是可重用的,稍后我們將向此組件添加更多內容,
// src/Modal.vue
<template>
<div class="modal">
<slot></slot>
</div>
</template>
復制代碼
多根模板
現在讓我們為我們的根組件創建模板,我們將創建一個按鈕來打開模態,它將觸發 toggleModalState 方法,
我們還將使用我們剛剛創建的modal組件,它將根據 modalState 的值來渲染,讓我們也在槽中插入一段文字作為內容,
// src/App.vue
<template>
<button @click="toggleModalState">Open modal</button>
<modal v-if="modalOpen">
<p>Hello, I'm a modal window.</p>
</modal>
</template>
<script>
import Modal from "./Modal.vue";
export default {
components: {
Modal
},
...
}
</script>
復制代碼
注意這個模板有什么奇怪的地方嗎?再看一遍,
沒錯——有兩個根元素,在Vue 3中,由于有了一個叫做片段(fragments)的功能,它不再強制要求有一個單一的根元素!
使用Composition API進行重構
Vue 3的旗艦功能是Composition API,這個新的API允許你使用 setup 功能而不是使用添加到組件定義物件的屬性來定義組件功能,
現在,讓我們重構App組件以使用Composition API,
在解釋代碼之前,請清楚我們所做的只是重構——組件的功能將相同,還要注意,模板沒有更改,因為Composition API僅影響我們定義組件功能的方式,而不影響我們渲染它的方式,
src/App.vue
<template>
<button @click="toggleModalState">Open modal</button>
<modal v-if="modalOpen">
<p>Hello, I'm a modal window.</p>
</modal>
</template>
<script>
import Modal from "./Modal.vue";
import { ref } from "vue";
export default {
setup () {
const modalState = ref(false);
const toggleModalState = () => {
modalState.value = https://www.cnblogs.com/chengxuyuanaa/p/!modalState.value;
};
return {
modalState,
toggleModalState
}
}
};
</script>
復制代碼
setup 方法
首先,請注意,我們匯入了 ref 函式,該函式允許我們定義回應式變數 modalState,此變數等效于this.modalState,
toggleModalState 方法只是一個普通的JavaScript函式,但是,請注意,要更改方法主體中的 modalState 值,我們需要更改其子屬性 value, 這是因為使用 ref 創建的回應式變數被封裝在一個物件中,這對于保留它們的回應式是非常必要的,因為它們在被傳遞的程序中會被保留下來,
最后,我們從 setup 方法回傳 modalState 和 toggleModalState ,因為這些是在呈現模板時傳遞給模板的值,
變化的原因
請記住,Composition API并不是更改,因為它純粹是可選的,主要動機是允許更好的代碼組織和組件之間的代碼重用(因為mixin本質上是一種反模式),
如果你認為在這個例子中重構App組件以使用Composition API是沒有必要的,那你的想法是正確的,但是,如果這是一個更大的組件,或者我們需要與其他組件共享其功能,那么你就會發現它的用處,
Teleporting content
如果你曾經創建過模態功能,你會知道它通常被放置在關閉的 </body> 標簽之前,
<body>
<div>
<!--main page content here-->
</div>
<!--modal here-->
</body>
復制代碼
這樣做是因為模式通常具有覆寫頁面的背景,要使用CSS來實作,您不需要處理父元素定位和z-index堆疊背景關系,因此最簡單的解決方案是將模式放在DOM的最底部,
但這在Vue.js中產生了一個問題,它假定UI將作為一個單一的組件樹來構建,為了允許將樹的片段移動到DOM中的其他位置,在Vue 3中添加了一個新的 teleport 組件,
要使用teleport,首先要在頁面上添加一個元素,我們要將模態內容移動到該頁面,我們將轉到 index.html,并將ID為 modal-wrapper 的 div 放在Vue的安裝元素旁邊,
index.html
<body>
...
<div id="app"></div><!--Vue mounting element-->
<div id="modal-wrapper">
<!--modal should get moved here-->
</div>
</body>
復制代碼
現在,回到 App.vue,我們將模態內容包裝在 teleport 組件中,我們還需要指定一個 to 屬性,為該屬性分配一個查詢選擇器,以標識目標元素,在本例中為 #modal-wrapper,
src/App.vue
<template>
<button @click="toggleModalState">Open modal</button>
<teleport to="#modal-wrapper">
<modal v-if="modalOpen">
<p>Hello, I'm a modal window.</p>
</modal>
</teleport>
</template>
復制代碼
就是這樣,teleport 中的任何內容都將渲染在目標元素中,
Emitting 和 event
現在,讓我們在modal中添加一個按鈕,讓它可以被關閉,要做到這一點,我們要在modal 模板中添加一個按鈕元素,并添加一個點擊處理程式,該處理程式會發出一個 close 事件,
src/Modal.vue
<template>
<div class="modal">
<slot></slot>
<button @click="$emit('close')">Dismiss</button>
</div>
</template>
復制代碼
然后,該事件將由父組件捕獲,并將切換 modalState 的值,從邏輯上將其設定為 false 并導致視窗關閉,
src/App.vue
<template>
...
<modal
v-if="modalOpen"
@click="toggleModalState"
>
<p>Hello, I'm a modal window.</p>
</modal>
</teleport>
</template>
復制代碼
到目前為止,此功能與Vue 2中的功能相同,但是,現在在Vue 3中,建議您使用新的 emits 組件選項顯式宣告組件的事件,就像props一樣,你可以簡單地創建一個字串陣列來命名組件將發出的每個事件,
src/Modal.vue
<template>...</template>
<script>
export default {
emits: [ "close" ]
}
</script>
復制代碼
變化的原因
想象一下,打開別人寫的組件的檔案,看到它的prop和event明文宣告,馬上,你就會明白這個組件的界面,也就是它要發送和接收什么,
除了提供自說明代碼外,你還可以使用事件宣告來驗證你的事件有效載荷,雖然我在這個例子中找不到理由來驗證,
了解更多:Emits Option RFC
樣式插槽內容
為了使模態可重用,我們提供了一個內容插槽,讓我們開始通過為組件添加 style 標簽來為內容設定樣式,
在我們的組件中使用 scoped CSS是一種很好的做法,以確保我們提供的規則不會對頁面中的其他內容產生意外影響,
讓我們把任何被放入插槽中的段落文字變成斜體,要做到這一點,我們將使用 p 選擇器創建一個新的CSS規則,
src/Modal.vue
<template>...</template>
<script>...</script>
<style scoped>
p {
font-style: italic;
}
</style>
復制代碼
如果你嘗試一下,你會發現這一點并不奏效,問題是,在編譯時,當插槽內容仍屬于父物件時,Scoped styling是在編譯時確定的,
Vue 3提供的解決方案是提供一個偽選擇器 ::v-slotted(),允許你在提供插槽的組件中使用范圍化規則來針對插槽內容,
這是我們的用法:
<style scoped>
::v-slotted(p) {
font-style: italic;
}
</style>
復制代碼
Vue 3還包含了其他一些新的Scoped Styling選擇器:::v-deep 和 ::v-global,你可以在這里了解更多:Scoped Styles RFC,
其他改變
好吧,這就是我可以在一個簡單示例中涵蓋的所有新功能,主要的我基本都有了,但這里有一些我認為很重要的,在總結文章之前,我覺得足夠重要,可以自己研究一下,
添加的:
- Global API treeshaking
移出的:
- Filters
- Inline templates
- Event interface for components(不再有event bus)
更改的:
- Async component API
- Custom directive API
- Render function syntax
關于Vue Router也有各種變化,但我將專門用一篇文章來介紹這些變化!

本文的文字及圖片來源于網路加上自己的想法,僅供學習、交流使用,不具有任何商業用途,著作權歸原作者所有,如有問題請及時聯系我們以作處理
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/65739.html
標籤:JavaScript
上一篇:文本空白,溢位,省略號
下一篇:寫一個擴展性較強的搜索主頁
