創建一個 template
組件來說,大多代碼在Vue2和Vue3都非常相似。Vue3支持碎片(Fragments)
,就是說在組件可以擁有多個根節點。
這種新特性可以減少很多組件之間的div
包裹元素。在開發vue的時候,我們會發現每一個組件都會有個div
元素包裹着。就會出現很多層多余的div
元素。碎片(Fragments)
解決了這個問題。對於有完美強迫症的童鞋“真的時太棒了”。我們這里的例子里就不展示了,用簡單的單根節點的組件。
Vue2 表格template
<template> <div class='form-element'> <h2> {{ title }} </h2> <input type='text' v-model='username' placeholder='Username' /> <input type='password' v-model='password' placeholder='Password' /> <button @click='login'> Submit </button> <p> Values: {{ username + ' ' + password }} </p> </div> </template>
在Vue3的唯一真正的不同在於數據獲取。Vue3中的反應數據(Reactive Data)
是包含在一個反應狀態(Reactive State)
變量中。— 所以我們需要訪問這個反應狀態來獲取數據值。
<template> <div class='form-element'> <h2> {{ state.title }} </h2> <input type='text' v-model='state.username' placeholder='Username' /> <input type='password' v-model='state.password' placeholder='Password' /> <button @click='login'> Submit </button> <p> Values: {{ state.username + ' ' + state.password }} </p> </div> </template>
建立數據 data
這里就是Vue2與Vue3 最大的區別 — Vue2使用選項類型API(Options API)
對比Vue3合成型API(Composition API)
舊的選項型API在代碼里分割了不同的屬性(properties):data,computed屬性,methods,等等。新的合成型API能讓我們用方法(function)來分割,相比於舊的API使用屬性來分組,這樣代碼會更加簡便和整潔。
現在我們來對比一下Vue2寫法和Vue3寫法在代碼里面的區別。
Vue2 - 這里把兩個數據放入data屬性中
export default { props: { title: String }, data () { return { username: '', password: '' } } }
在Vue3.0,我們就需要使用一個新的setup()
方法,此方法在組件初始化構造的時候觸發。
為了可以讓開發者對反應型數據有更多的控制,我們可以直接使用到 Vue3 的反應API(reactivity API)
。
使用以下三步來建立反應性數據
:
- 從vue引入
reactive
- 使用
reactive()
方法來聲名我們的數據為反應性數據 - 使用
setup()
方法來返回我們的反應性數據,從而我們的template可以獲取這些反應性數據
上一波代碼,讓大家更容易理解是怎么實現的。
import { reactive } from 'vue' export default { props: { title: String }, setup () { const state = reactive({ username: '', password: '' }) return { state } } }
這里構造的反應性數據就可以被template
使用,可以通過state.username
和state.password
獲得數據的值。
Vue2 對比 Vue3的 methods
編寫
Vue2 的選項型API是把methods分割到獨立的屬性區域的。我們可以直接在這個屬性里面添加方法來處理各種前端邏輯。
export default { props: { title: String }, data () { return { username: '', password: '' } }, methods: { login () { // 登陸方法 } } }
Vue3 的合成型API里面的setup()
方法也是可以用來操控methods的。創建聲名方法其實和聲名數據狀態是一樣的。— 我們需要先聲名一個方法然后在setup()
方法中返回(return)
, 這樣我們的組件內就可以調用這個方法了。
export default { props: { title: String }, setup () { const state = reactive({ username: '', password: '' }) const login = () => { // 登陸方法 } return { login, state } } }
生命周期鈎子 — Lifecyle Hooks
在 Vue2,我們可以直接在組件屬性中調用Vue的生命周期的鈎子。以下使用一個組件已掛載(mounted)
生命周期觸發鈎子。
export default { props: { title: String }, data () { return { username: '', password: '' } }, mounted () { console.log('組件已掛載') }, methods: { login () { // login method } } }
現在 Vue3 的合成型API里面的setup()
方法可以包含了基本所有東西。生命周期的鈎子就是其中之一!
但是在 Vue3 生周期鈎子不是全局可調用的了,需要另外從vue中引入。和剛剛引入reactive
一樣,生命周期的掛載鈎子叫onMounted
。
引入后我們就可以在setup()
方法里面使用onMounted
掛載的鈎子了。
import { reactive, onMounted } from 'vue' export default { props: { title: String }, setup () { // .. onMounted(() => { console.log('組件已掛載') }) // ... } }
計算屬性 - Computed Properties
我們一起試試添加一個計算屬性來轉換username
成小寫字母。
在 Vue2 中實現,我們只需要在組件內的選項屬性中添加即可
export default { // .. computed: { lowerCaseUsername () { return this.username.toLowerCase() } } }
Vue3 的設計模式給予開發者們按需引入需要使用的依賴包。這樣一來就不需要多余的引用導致性能或者打包后太大的問題。Vue2就是有這個一直存在的問題。
所以在 Vue3 使用計算屬性,我們先需要在組件內引入computed
。
使用方式就和反應性數據(reactive data)
一樣,在state
中加入一個計算屬性:
import { reactive, onMounted, computed } from 'vue' export default { props: { title: String }, setup () { const state = reactive({ username: '', password: '', lowerCaseUsername: computed(() => state.username.toLowerCase()) }) // ... }
接收 Props
接收組件props
參數傳遞這一塊為我們帶來了Vue2和Vue3之間最大的區別。—this
在vue3中與vue2代表着完全不一樣的東西。
在 Vue2,this
代表的是當前組件,不是某一個特定的屬性。所以我們可以直接使用this
訪問prop屬性值。就比如下面的例子在掛載完成后打印處當前傳入組件的參數title
。
mounted () { console.log('title: ' + this.title) }
但是在 Vue3 中,this
無法直接拿到props屬性,emit events(觸發事件)和組件內的其他屬性。不過全新的setup()
方法可以接收兩個參數:
props
- 不可變的組件參數context
- Vue3 暴露出來的屬性(emit,slots,attrs)
所以在 Vue3 接收與使用props就會變成這樣:
setup (props) { // ... onMounted(() => { console.log('title: ' + props.title) }) // ... }
事件 - Emitting Events
在 Vue2 中自定義事件是非常直接的,但是在 Vue3 的話,我們會有更多的控制的自由度。
舉例,現在我們想在點擊提交按鈕時觸發一個login
的事件。
在 Vue2 中我們會調用到this.$emit
然后傳入事件名和參數對象。
login () { this.$emit('login', { username: this.username, password: this.password }) }
但是在 Vue3中,我們剛剛說過this
已經不是和vue2代表着這個組件了,所以我們需要不一樣的自定義事件的方式。
那怎么辦呀?! ლಠ益ಠ)ლ
不用慌,在setup()
中的第二個參數content
對象中就有emit
,這個是和this.$emit
是一樣的。那么我們只要在setup()
接收第二個參數中使用分解對象法取出emit
就可以在setup方法中隨意使用了。
然后我們在login
方法中編寫登陸事件:
setup (props, { emit }) { // ... const login = () => { emit('login', { username: state.username, password: state.password }) } // ... }
最終的vue2對比vue3代碼
真的是太棒了,能看到這里的童鞋們,你們現在基本都看到vue2與vue3其實概念與理念都是一樣的。只是有一些屬性獲取方式和聲名和定義方式稍微變了。一直在鬼哭狼嚎的小小前端開發猿人們,你們可以松一口氣了吧。
總結一下,我覺得 Vue3 給我們前端開發者帶來了全新的開發體驗,更好的使用彈性,可控度也得到了大大的提升。如果你是一個學過或者接觸過 React 然后現在想使用Vue的話,應該特別興奮,因為很多使用方式都和React非常相近了 !
全新的合成式API(Composition API)
可以提升代碼的解耦程度 —— 特別是大型的前端應用,效果會更加明顯。還有就是按需引用的有了更細微的可控性,讓項目的性能和打包大小有更好的控制。
最后我把完成的 Vue2 和 Vue3 的組件代碼發出來給大家:
Vue2
<template> <div class='form-element'> <h2> {{ title }} </h2> <input type='text' v-model='username' placeholder='Username' /> <input type='password' v-model='password' placeholder='Password' /> <button @click='login'> Submit </button> <p> Values: {{ username + ' ' + password }} </p> </div> </template> <script> export default { props: { title: String }, data () { return { username: '', password: '' } }, mounted () { console.log('title: ' + this.title) }, computed: { lowerCaseUsername () { return this.username.toLowerCase() } }, methods: { login () { this.$emit('login', { username: this.username, password: this.password }) } } } </script>
Vue3
<template> <div class='form-element'> <h2> {{ state.title }} </h2> <input type='text' v-model='state.username' placeholder='Username' /> <input type='password' v-model='state.password' placeholder='Password' /> <button @click='login'> Submit </button> <p> Values: {{ state.username + ' ' + state.password }} </p> </div> </template> <script> import { reactive, onMounted, computed } from 'vue' export default { props: { title: String }, setup (props, { emit }) { const state = reactive({ username: '', password: '', lowerCaseUsername: computed(() => state.username.toLowerCase()) }) onMounted(() => { console.log('title: ' + props.title) }) const login = () => { emit('login', { username: state.username, password: state.password }) } return { login, state } } } </script>
希望這篇文章能讓大家體驗到一個比較全面的Vue2與Vue3的開發區別。