今年7月,尤大大宣佈 Vue 3 進入 RC 階段,這意味着 Vue 3 內核 API 與實現已趨穩定。vue
Vue做爲一種漸進式框架, 借鑑了 React 的組件化和虛擬 DOM ,借鑑了 Angular 的模塊化和雙向數據綁定。就框架的 API 而言,對比之下,它更加輕便簡潔。對於Vue的好處這裏再也不贅述。node
相對vue2.x,Vue3作了不少重要的變動,特別是Composition API的引入。咱們知道,Vue 現有 API 是經過「選項」組織代碼的,隨着功能的增加,複雜組件的代碼會變得愈來愈難維護,不少邏輯都沒法複用。開發的時候複雜的組件千行代碼template/data/methods來回翻,看到你頭暈,而vue3可讓你在接手別人的代碼時更容易理清邏輯關係。下面直接進入主題,咱們來看看Vue3都有哪些新特性,相對於以前版本又有哪些變動。react
Vue 3.0 相對與以前的版本,有 6 個方面的重要變動:數組
性能上,主要是優化了虛擬 DOM,因此也就有了更加優化的編譯,同時實現了更加高效的組件初始化。app
在大部分狀況下,咱們並不須要 vue 中的全部功能,可是在以前的 vue 版本中,咱們沒有一個合適的辦法用來除去不須要的功能,而 Vue3 中,爲了知足體積更小的需求,支持 Tree-shaking,也就意味着咱們能夠按需求引用的內置的指令和方法。框架
Composition API 主要是提升了代碼邏輯的可複用性,而且將 Reactivity 模塊獨立出來,這也使得 vue 3 變得更加靈活地與其餘框架組合使用。dom
在書寫vue2時,因爲組件必須只有一個根節點,不少時候會添加一些沒有意義的節點用於包裹。Fragment組件就是用於解決這個問題的(這和React中的Fragment組件是同樣的)。異步
-Manual render functions can simply return Arrays (render 函數能夠返回數組)async
Teleport其實就是React中的Portal。Portal 提供了一種將子節點渲染到存在於父組件之外的 DOM 節點的優秀的方案。一個 portal 的典型用例是當父組件有 overflow: hidden 或 z-index 樣式時,但你須要子組件可以在視覺上「跳出」其容器。例如,對話框、懸浮卡以及提示框。ide
一樣的,這和React中的Supense是同樣的。Suspense 讓你的組件在渲染以前進行「等待」,並在等待時顯示 fallback 的內容。
vue3.0 對 TS 的支持度更高了,同時也支持 TSX 的使用;API 在 JS 與 TS 中的使用相同;類組件仍然可用,可是須要咱們引入 vue-class-component@next,該模塊目前還處於 alpha 測試階段。
自定義 render 會提供一個 API 用來建立自定義的 render,所以再也不須要爲了自定義一些功能而 fork Vue 的代碼。這個特性給 Weex 和 NativeScript Vue 這樣的項目提供了不少便利。
在vue3中引入了Composition API(組合API),使用純函數分隔複用代碼,讓邏輯變得清晰。
關於VCA,有人說跟react的hooks很像,咱們來看看做者尤大的介紹:
新版的生命週期函數,能夠按需導入到組件中,且只能在 setup() 函數中使用.
import {onBeforeMount, onMounted} from 'vue' export default { setup() { onBeforeMount(() => { console.log('onBeforeMount') }) onMounted(() => { console.log('onMounted') }) }, }
setup() 函數是 vue3 中,專門爲組件提供的新屬性。它爲咱們使用 vue3 的 Composition API 新特性提供了統一的入口。
export default { props: { str: String }, setup(props, context) { console.log(props) // str console.log(context) // attrs, slots, parent, root, emit, refs }, }
reactive() 函數接收一個普通對象,返回一個響應式的數據對象。
import { reactive } from 'vue' export default { setup() { const state = reactive({count: 0}) // 建立響應式數據對象 return state //將響應式數據對象 return 出去,供 template 使用 } }
ref() 函數根據給定的值建立一個響應式的數據對象,返回值是一個對象,這個對象上只包含一個 .value 屬性
import { ref } from 'vue' export default { setup() { const count = ref(0) // 建立響應式數據對象 count,初始值爲 0 console.log(count.value) // 在setup內訪問count值須要.value 屬性才能夠,但在template中能夠直接訪問 return { count } }, }
toRefs() 函數能夠將 reactive() 建立出來的響應式對象,轉換爲普通的對象,只不過,這個對象上的每一個屬性節點,都是 ref() 類型的響應式數據
import { reactive, toRefs } from 'vue' export default { setup() { const state = reactive({count: 0, name:'weedsFly'}) // 用reactive集中建立多個響應式對象 const add = () => { // methods寫在setup內 state.count++ } return { // ...state, // 使用展開運算符後 用reactive建立的響應式數據 變成了 固定的值 ...toRefs(state), // 能夠用toRefs函數 將傳進來的非響應式對象 轉成 ref() 類型的響應式數據 add } }, }
經過 ref() 還能夠引用頁面上的元素或組件,這點和vue2的ref概念相似。
1.元素引用
import { ref, onMounted } from 'vue' export default { setup() { const h1Ref = ref(null) // 建立一個 DOM 引用 onMounted(() => { // 在 DOM 首次加載完畢以後,才能獲取到元素的引用 h1Ref.value.style.color = 'pink' // h1Ref.value 是原生DOM對象 }) return { h1Ref } } }
2.組件引用
//父組件: import { ref } from 'vue' export default { setup() { const compRef = ref(null) // 建立一個組件的 ref 引用 showCompData = () => { // 展現子組件中 count 的值 console.log(compRef.value.count) } return { compRef, showCompData } } }
//子組件: import { ref } from 'vue' export default { setup() { const count = ref(0) // 定義響應式的數據 return { count } } }
omputed() 用來建立計算屬性,computed() 函數的返回值是一個 ref 的實例。
1.computed建立只讀的計算屬性(傳入一個 function 函數,能夠獲得一個只讀的計算屬性)
import { ref, computed } from 'vue' export default { setup() { const count = ref(0) const computedCount = computed(() => count.value + 1) computedCount.value = 9 // computed value is readonly. return { count, computedCount } }, }
2.computed建立可讀可寫的計算屬性
import { ref, computed } from 'vue' export default { setup() { const count = ref(0) const computedCount = computed({ get: () => count.value + 1, set: val => { count.value = val - 1 } }) computedCount.value = 100 // 爲計算屬性賦值的操做,會觸發 set 函數 console.log(count.value) // 觸發 set 函數後,count 的值會被更新 return { count, computedCount, computedCount } }, }
1.監視單個數據源變更
import { reactive, watch } from 'vue' export default { setup() { const state = reactive({count: 100}) watch( () => state.count, (newVal, oldVal) => { console.log(newVal, oldVal)}, {lazy: true} // 在 watch 被建立的時候,不執行回調函數中的代碼 ) setTimeout(() => { state.count++ }, 1500) } }
import { ref, watch } from 'vue' export default { setup() { const count = ref(100) watch( count, (newVal, oldVal) => { console.log(newVal, oldVal)}, {lazy: true} // 在 watch 被建立的時候,不執行回調函數中的代碼 ) setTimeout(() => { count++ }, 1500) } }
2.監視多個數據源
import { reactive, watch } from 'vue' export default { setup() { const state = reactive({count: 100, name: 'Laiyj'}) watch( [() => state.count, () => state.name], ([newCount, newName], [oldCount, oldName]) => { console.log(newCount, oldCount) console.log(newName, oldName) }, {lazy: true} // 在 watch 被建立的時候,不執行回調函數中的代碼 ) setTimeout(() => { state.count++ state.name = 'Lucy' }, 1000) } }
import { ref, watch } from 'vue' export default { setup() { const count = ref(100) const name = ref('Laiyj') watch( [count, name], ([newCount, newName], [oldCount, oldName]) => { console.log(newCount, oldCount) console.log(newName, oldName) }, {lazy: true} // 在 watch 被建立的時候,不執行回調函數中的代碼 ) setTimeout(() => { count++ name = 'Lucy' }, 1000) } }
3.清除watch監視
import { ref, watch } from 'vue' export default { setup() { const count = ref(100) const stop = watch( // 建立監視,並獲得 中止函數 count, (newVal, oldVal) => { console.log('I am watching.') console.log(newVal, oldVal) }, {lazy: true} // 在 watch 被建立的時候,不執行回調函數中的代碼 ) setTimeout(() => { count++ }, 1000) const clearWatch = () => { stop() } return { count, clearWatch } } }
4.在 watch 中清除無效的異步任務(與節流防抖同效)
import { ref, watch } from 'vue' export default { setup() { const keyword = ref('') const asyncPrint = (val) => { // 執行異步任務,並獲得關閉異步任務的 timerId return setTimeout(() => { console.log(val) }, 1000) } watch( keyword, (newVal, oldVal, onClean) => { const timeId = asyncPrint() onClean(() => {clearTimeout(timeId)}) // 若是 watch 監聽被重複執行了,則會先清除上次未完成的異步任務 } ) return { keyword } } }
//父組件: import { provide, watch } from 'vue' export default { setup() { const color = ref('red') provide('themeColor', color) // 父組件經過 provide 函數向子級組件共享數據(不限層級) provide('要共享的數據名稱', 被共享的數據) const changeColor = (val) => { color.value = val } return { color, changeColor } } }
// 子級組件: import { inject, watch } from 'vue' export default { setup() { const color = inject('color') // 調用 inject 函數時,經過指定的數據名稱,獲取到父級共享的數據 return { color } } }
以上只羅列了幾個比較基礎重要的API,vue3還有不少還須要多多學習 : )