VUE3安裝使用新特性介紹

VUE3 需要使用 Vue CLI v4.5

安裝vue-cli 4.5

npm install -g @vue/cli@next
# OR
yarn global add @vue/cli@next

查看vue版本

vue --version  //查看版本 @vue/cli 4.5.12

創建vue3項目

vue create hello-world //創建一個項目

手動選擇

image.png
image.png

vue3新特性

更快 (Proxy重構虛擬dom功能)
更小 (支持tree-shaking,沒有用到的方法(代碼)最后不會被打包到最終的包中。這可以優化項目體積)
更易于維護 (Function-based API 代替傳統的Class API ,摒棄高階組件。
優勢:復用簡單,把要復用的邏輯抽取到函數中(如mixin))
更多原生支持 (支持TS 3.0源碼使用TS編寫(Typescript))
更易于開發使用 (Observer模塊已被解壓縮到自己的包中,允許使用它)
重寫虛擬DOM (patch flag(補丁標記),會忽略所有的靜態節點,只對有標記的動態節點進行對比,而且在多層的嵌套下依然有效)
優化插槽生成 (單獨重新渲染父組件和子組件)
靜態樹提升 (這意味著vue3的編譯器能夠檢測到什么是靜態組件,然后將其提升,從而降低了渲染成本)
基于Proxy的觀察者機制

VUE2與VUE3的區別

創建一個 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>


全局方法現在在app實例上

const app = Vue.createApp({})

app.use

建立數據 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()方法,此方法在組件初始化構造的時候觸發。setup()函數是vue3中專門新增的方法,可以理解為Composition Api的入口。在beforecreate之后,create之前執行。

為了可以讓開發者對反應型數據有更多的控制,我們可以直接使用到 Vue3 的反應API(reactivity API)

使用以下三步來建立反應性數據:

  1. 從vue引入reactive
  2. 使用reactive()方法來聲名我們的數據為反應性數據
  3. 使用setup()方法來返回我們的反應性數據,從而我們的template可以獲取這些反應性數據

上一波代碼,讓大家更容易理解是怎么實現的。

import { reactive } from 'vue'

export default {
  props: {
    title: String
  },
  setup () {
    const state = reactive({
      username: '',
      password: ''
    })

    return { state }
  }
}

這里構造的反應性數據就可以被template使用,可以通過state.usernamestate.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('組件已掛載')
    })

    // ...
  }
}


LifeCycle(Hooks) 3.0當中的生命周期與2.0的生命周期出現了很大的不同:

beforeCreate -> 請使用 setup()

created -> 請使用 setup()

beforeMount -> onBeforeMount

mounted -> onMounted

beforeUpdate -> onBeforeUpdate

updated -> onUpdated

beforeDestroy -> onBeforeUnmount

destroyed -> onUnmounted

errorCaptured -> onErrorCaptured

計算屬性 - 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代表著完全不一樣的東西。

Vue2this代表的是當前組件,不是某一個特定的屬性。所以我們可以直接使用this訪問prop屬性值。就比如下面的例子在掛載完成后打印處當前傳入組件的參數title

mounted () {
    console.log('title: ' + this.title)
}

但是在 Vue3 中,this無法直接拿到props屬性,emit events(觸發事件)和組件內的其他屬性。不過全新的setup()方法可以接收兩個參數:

  1. props - 不可變的組件參數
  2. 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)可以提升代碼的解耦程度 —— 特別是大型的前端應用,效果會更加明顯。還有就是按需引用的有了更細微的可控性,讓項目的性能和打包大小有更好的控制。

最后我把完成的 Vue2Vue3 的組件代碼發出來給大家:

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>
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容