讓你30分鐘快速掌握vue3教程
經過了漫長的迭代,Vue 3.0終於在上2020-09-18釋出了,帶了翻天覆地的變化,使用了Typescript 進行了大規模的重構,帶來了Composition API RFC版本,類似React Hook 一樣的寫Vue,可以自定義自己的hook ,讓使用者更加的靈活,接下來總結一下vue 3.0 帶來的部分新特性。
- setup()
- ref()
- reactive()
- isRef()
- toRefs()
- computed()
- watch()
- LifeCycle Hooks(新的生命週期)
- Template refs
- globalProperties
- Suspense
Vue2與Vue3的對比
- 對TypeScript支援不友好(所有屬性都放在了this物件上,難以推倒元件的資料型別)
- 大量的API掛載在Vue物件的原型上,難以實現TreeShaking。
- 架構層面對跨平臺dom渲染開發支援不友好
- CompositionAPI。受ReactHook啟發
- 更方便的支援了 jsx
- Vue 3 的 Template 支援多個根標籤,Vue 2 不支援
- 對虛擬DOM進行了重寫、對模板的編譯進行了優化操作...
一、setup 函式
setup() 函式是 vue3 中,專門為元件提供的新屬性。它為我們使用 vue3 的 Composition API 新特性提供了統一的入口,setup 函式會在 beforeCreate 之後、created 之前執行,vue3也是取消了這兩個鉤子,統一用setup代替,該函式相當於一個生命週期函式,vue中過去的data,methods,watch等全部都用對應的新增api寫在setup()函式中
setup(props,context) { context.attrs context.slots context.parent context.root context.emit context.refs return { } }
- props: 用來接收 props 資料
- context 用來定義上下文,上下文物件中包含了一些有用的屬性,這些屬性在 vue 2.x 中需要通過 this 才能訪問到,在 setup() 函式中無法訪問到 this,是個 undefined
- 返回值: return {},返回響應式資料,模版中需要使用的函式
二、reactive 函式
reactive() 函式接收一個普通物件,返回一個響應式的資料物件,想要使用建立的響應式資料也很簡單,創建出來之後,在setup中return出去,直接在template中呼叫即可
<template> {{name}} // test <template> <script lang="ts"> import { defineComponent,reactive,ref,toRefs } from 'vue'; export default defineComponent({ setup(props,context) { let state = reactive({ name: 'test' }); return state } }); </script>
三、ref() 函式
ref() 函式用來根據給定的值建立一個響應式的資料物件,ref() 函式呼叫的返回值是一個物件,這個物件上只包含一個 value 屬性,只在setup函式內部訪問ref函式需要加.value
<template> <div class="mine"> {{count}} // 10 </div> </template> <script lang="ts"> import { defineComponent,ref } from 'vue'; export default defineComponent({ setup() { const count = ref<number>(10) // 在js 中獲取ref 中定義的值,需要通過value屬性 console.log(count.value); return { count } } }); </script>
在 reactive 物件中訪問 ref 建立的響應式資料
<template> <div class="mine"> {{count}} -{{t}} // 10 -100 </div> </template> <script lang="ts"> import { defineComponent,toRefs } from 'vue'; export default defineComponent({ setup() { const count = ref<number>(10) const obj = reactive({ t: 100,count }) // 通過reactive 來獲取ref 的值時,不需要使用.value屬性 console.log(obj.count); return { ...toRefs(obj) } } }); </script>
四、isRef() 函式
isRef() 用來判斷某個值是否為 ref() 創建出來的物件
<script lang="ts"> import { defineComponent,isRef,ref } from 'vue'; export default defineComponent({ setup(props,context) { const name: string = 'vue' const age = ref<number>(18) console.log(isRef(age)); // true console.log(isRef(name)); // false return { age,name } } }); </script>
五、toRefs() 函式
toRefs() 函式可以將 reactive() 創建出來的響應式物件,轉換為普通的物件,只不過,這個物件上的每個屬性節點,都是 ref() 型別的響應式資料
<template> <div class="mine"> {{name}} // test {{age}} // 18 </div> </template> <script lang="ts"> import { defineComponent,context) { let state = reactive({ name: 'test' }); const age = ref(18) return { ...toRefs(state),age } } }); </script>
六、computed()
該函式用來創造計算屬性,和過去一樣,它返回的值是一個ref物件。 裡面可以傳方法,或者一個物件,物件中包含set()、get()方法
6.1 建立只讀的計算屬性
import { computed,defineComponent,context) { const age = ref(18) // 根據 age 的值,建立一個響應式的計算屬性 readOnlyAge,它會根據依賴的 ref 自動計算並返回一個新的 ref const readOnlyAge = computed(() => age.value++) // 19 return { age,readOnlyAge } } }); </script>
6.2 通過set()、get()方法建立一個可讀可寫的計算屬性
<script lang="ts"> import { computed,context) { const age = ref<number>(18) const computedAge = computed({ get: () => age.value + 1,set: value => age.value + value }) // 為計算屬性賦值的操作,會觸發 set 函式,觸發 set 函式後,age 的值會被更新 age.value = 100 return { age,computedAge } } }); </script>
七、 watch() 函式
watch 函式用來偵聽特定的資料來源,並在回撥函式中執行副作用。預設情況是懶執行的,也就是說僅在偵聽的源資料變更時才執行回撥。
7.1 監聽用reactive宣告的資料來源
<script lang="ts"> import { computed,toRefs,watch } from 'vue'; interface Person { name: string,age: number } export default defineComponent({ setup(props,context) { const state = reactive<Person>({ name: 'vue',age: 10 }) watch( () => state.age,(age,preAge) => { console.log(age); // 100 console.log(preAge); // 10 } ) // 修改age 時會觸發watch 的回撥,列印變更前後的值 state.age = 100 return { ...toRefs(state) } } }); </script>
7.2 監聽用ref宣告的資料來源
<script lang="ts"> import { defineComponent,context) { const age = ref<number>(10); watch(age,() => console.log(age.value)); // 100 // 修改age 時會觸發watch 的回撥,列印變更後的值 age.value = 100 return { age } } }); </script>
7.3 同時監聽多個值
<script lang="ts"> import { computed,age: 10 }) watch( [() => state.age,() => state.name],([newName,newAge],[oldName,oldAge]) => { console.log(newName); console.log(newAge); console.log(oldName); console.log(oldAge); } ) // 修改age 時會觸發watch 的回撥,列印變更前後的值,此時需要注意,更改其中一個值,都會執行watch的回撥 state.age = 100 state.name = 'vue3' return { ...toRefs(state) } } }); </script>
7.4 stop 停止監聽
在 setup() 函式內建立的 watch 監視,會在當前元件被銷燬的時候自動停止。如果想要明確地停止某個監視,可以呼叫 watch() 函式的返回值即可,語法如下:
<script lang="ts"> import { set } from 'lodash'; import { computed,age: 10 }) const stop = watch( [() => state.age,都會執行watch的回撥 state.age = 100 state.name = 'vue3' setTimeout(()=> { stop() // 此時修改時,不會觸發watch 回撥 state.age = 1000 state.name = 'vue3-' },1000) // 1秒之後講取消watch的監聽 return { ...toRefs(state) } } }); </script>
八、LifeCycle Hooks(新的生命後期)
新版的生命週期函式,可以按需匯入到元件中,且只能在 setup() 函式中使用,但是也可以在setup 外定義,在 setup 中使用
<script lang="ts"> import { set } from 'lodash'; import { defineComponent,onBeforeMount,onBeforeUnmount,onBeforeUpdate,onErrorCaptured,onMounted,onUnmounted,onUpdated } from 'vue'; export default defineComponent({ setup(props,context) { onBeforeMount(()=> { console.log('beformounted!') }) onMounted(() => { console.log('mounted!') }) onBeforeUpdate(()=> { console.log('beforupdated!') }) onUpdated(() => { console.log('updated!') }) onBeforeUnmount(()=> { console.log('beforunmounted!') }) onUnmounted(() => { console.log('unmounted!') }) onErrorCaptured(()=> { console.log('errorCaptured!') }) return {} } }); </script>
九、Template refs
通過refs 來回去真實dom元素,這個和react 的用法一樣,為了獲得對模板內元素或元件例項的引用,我們可以像往常一樣在setup()中宣告一個ref並返回它
- 還是跟往常一樣,在 html 中寫入 ref 的名稱
- 在steup 中定義一個 ref
- steup 中返回 ref的例項
- onMounted 中可以得到 ref的RefImpl的物件,通過.value 獲取真實dom
<template> <!--第一步:還是跟往常一樣,在 html 中寫入 ref 的名稱--> <div class="mine" ref="elmRefs"> <span>1111</span> </div> </template> <script lang="ts"> import { set } from 'lodash'; import { defineComponent,context) { // 獲取真實dom const elmRefs = ref<null | HTMLElement>(null); onMounted (() => { console.log(elmRefs.value); // 得到一個 RefImpl 的物件,通過 .value 訪問到資料 }) return { elmRefs } } }); </script>
十、vue 的全域性配置
通過vue 例項上config來配置,包含Vue應用程式全域性配置的物件。您可以在掛載應用程式之前修改下面列出的屬性:
const app = Vue.createApp({}) app.config = {...}
為元件渲染功能和觀察程式期間的未捕獲錯誤分配處理程式。錯誤和應用程式例項將呼叫處理程式
app.config.errorHandler = (err,vm,info) => {}
可以在應用程式內的任何元件例項中訪問的全域性屬性,元件的屬性將具有優先權。這可以代替Vue 2.xVue.prototype擴充套件:
const app = Vue.createApp({}) app.config.globalProperties.$http = 'xxxxxxxxs'
可以在元件用通過 getCurrentInstance() 來獲取全域性globalProperties 中配置的資訊,getCurrentInstance 方法獲取當前元件的例項,然後通過 ctx 屬性獲得當前上下文,這樣我們就能在setup中使用router和vuex,通過這個屬性我們就可以操作變數、全域性屬性、元件屬性等等
setup( ) { const { ctx } = getCurrentInstance(); ctx.$http }
十一、Suspense 元件
在開始介紹 Vue 的 Suspense 元件之前,我們有必要先了解一下 React 的 Suspense 元件,因為他們的功能類似。
React.lazy 接受一個函式,這個函式需要動態呼叫 import()。它必須返回一個 Promise,該 Promise 需要 resolve 一個 default export 的 React 元件。
import React,{ Suspense } from 'react'; const myComponent = React.lazy(() => import('./Component')); function MyComponent() { return ( <div> <Suspense fallback={<div>Loading...</div>}> <myComponent /> </Suspense> </div> ); }
Vue3 也新增了 React.lazy 類似功能的 defineAsyncComponent 函式,處理動態引入(的元件)。defineAsyncComponent可以接受返回承諾的工廠函式。當您從伺服器檢索到元件定義時,應該呼叫Promise的解析回撥。您還可以呼叫reject(reason)來指示負載已經失敗
import { defineAsyncComponent } from 'vue' const AsyncComp = defineAsyncComponent(() => import('./components/AsyncComponent.vue') ) app.component('async-component',AsyncComp)
Vue3 也新增了 Suspense 元件:
<template> <Suspense> <template #default> <my-component /> </template> <template #fallback> Loading ... </template> </Suspense> </template> <script lang='ts'> import { defineComponent,defineAsyncComponent } from "vue"; const MyComponent = defineAsyncComponent(() => import('./Component')); export default defineComponent({ components: { MyComponent },setup() { return {} } }) </script>
十二、vue 3.x 完整元件模版結構
一個完成的vue 3.x 完整元件模版結構包含了:元件名稱、 props、components、setup(hooks、computed、watch、methods 等)
<template> <div class="mine" ref="elmRefs"> <span>{{name}}</span> <br> <span>{{count}}</span> <div> <button @click="handleClick">測試按鈕</button> </div> <ul> <li v-for="item in list" :key="item.id">{{item.name}}</li> </ul> </div> </template> <script lang="ts"> import { computed,getCurrentInstance,PropType,toRefs } from 'vue'; interface IState { count: 0,name: string,list: Array<object> } export default defineComponent({ name: 'demo',// 父元件傳子元件引數 props: { name: { type: String as PropType<null | ''>,default: 'vue3.x' },list: { type: Array as PropType<object[]>,default: () => [] } },components: { /// TODO 元件註冊 },emits: ["emits-name"],// 為了提示作用 setup (props,context) { console.log(props.name) console.log(props.list) const state = reactive<IState>({ name: 'vue 3.0 元件',count: 0,list: [ { name: 'vue',id: 1 },{ name: 'vuex',id: 2 } ] }) const a = computed(() => state.name) onMounted(() => { }) function handleClick () { state.count ++ // 呼叫父元件的方法 context.emit('emits-name',state.count) } return { ...toRefs(state),handleClick } } }); </script>
vue 3 的生態
- 官網
- 原始碼
- vite構建器
- 腳手架:https://cli.vuejs.org/
- vue-router-next
- vuex4.0
UI 元件庫
vant2.x
Ant Design of Vue 2.x
element-plus
到此這篇關於讓你30分鐘快速掌握vue3教程的文章就介紹到這了,更多相關vue3 入門內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!