2020年09月18日,vue3.0正式發佈。做爲一個大的版本更新,Vue3.0相比於 Vue2.0,天然有着不小的變化。前端
其中,Vue3的一大核心特性是引入了Composition API(組合式API),那麼相比於vue2.0,Composition API有什麼不同?vue
在Vue2.x中,組件的主要邏輯是經過一些配置項來編寫,包括一些內置的生命週期方法或者組件方法react
export default {
name: 'test',
components: {},
props: {},
data () {
return {}
},
created(){},
mounted () {},
watch:{},
methods: {}
}
複製代碼
咱們一般將components、data、以及各類鉤子和watch分開來寫,而後經過options的形式傳給vue實例。面試
setup() 函數是 vue3 中,專門爲組件提供的新屬性。它爲咱們使用 vue3 的 Composition API 新特性提供了統一的入口,通俗點來講就是啥玩意都能寫到setup()裏面。算法
import { fetchGetList } from '@/api/repositories'
import { ref, onMounted, watch, toRefs } from 'vue'
setup (props) {
const repositories = ref([])
const getList = async () => {
repositories.value = await fetchGetList()
}
onMounted(getUserRepositories)
watch(getUserRepositories)
return {
repositories,
getUserRepositories
}
}
複製代碼
咱們在進行組件式編程,同一個組件內可能要寫很是多的功能,好比彈框、getList、add、update之類,在vue2.0時代,咱們的組件代碼可能會這麼寫:typescript
export default {
name: '',
components: {
},
props: {
},
data() {
return {
// 踢足球
football: '',
// 打籃球
basketball: '',
// 打檯球
....
}
},
created() {
// 踢足球
// 打籃球
},
methods: {
// 踢足球
playFootball() {
console.log(this.football)
},
// 打籃球
playBasketball() {
console.log(this.basketball)
}
// 打檯球
....
}
}
</script>
複製代碼
分散在各個地方的邏輯片斷,使咱們的組件愈來愈難以閱讀,常常爲了看一個功能要瘋狂上下滑動屏幕,在各個區塊裏翻找和修改。編程
在vue2.0中還能夠用mixins來進行抽象,可是用的時間長了,mixins就沒那麼香了api
能夠將代碼按照功能組織區分緩存
存在衝突隱患,你有可能在使用過程當中出現屬性或函數的重名衝突markdown
依賴關係不清晰,特別是在多個Mixins存在交流的狀況下。
邏輯複用不夠靈活,若是你須要在不一樣的組件間差別化或配置化使用Mixins的話。
那麼vue3.0的組合式 API應該怎麼寫呢:
<script>
export default {
setup(props, ctx) {
// 踢足球
const useFootball = function(){
}
// 打籃球
const useBasketball = function(){
}
return {
useFootball,
useBasketball
}
}
};
</script>
複製代碼
沒有了各類分散的區塊,咱們能夠寫更少的代碼,也更容易將能夠複用的邏輯從組件裏抽出到函數裏。
在Vue2.x中經過組件data的方法來定義一些當前組件的數據:
data() {
return {
name: 'test',
list: [],
}
},
複製代碼
在Vue3中經過ref或者reactive建立響應式對象:
import {ref,reactive} from 'vue'
...
setup(){
const name = ref('test')
const state = reactive({
list: []
})
return {
name,
state
}
}
...
複製代碼
ref將給定的值建立一個響應式的數據對象並賦值初始值(int或者string),reactive能夠直接定義複雜響應式對象。爲何reactive能夠定義複雜的響應式對象這個後面會有說明。
在Vue2.x中,組件的方法中能夠經過this獲取到當前組件的實例,並執行data變量的修改,方法的調用,組件的通訊等等
可是在Vue3中,setup()在beforeCreate和created時機就已調用,沒法使用和Vue2.x同樣的this,可是能夠經過接收setup(props,ctx)的方法,獲取到當前組件的實例和props:
export default {
props: {
name: String,
},
setup(props,ctx) {
console.log(props.name)
ctx.emit('event')
},
}
複製代碼
vue2.0的源碼在處理虛擬DOM時,選擇的是將template模板內的全部內容遍歷,生成虛擬DOM,當有內容發生變化的時候,經過diff算法進行更新。可是HTML中除了雙向綁定的動態數據,還有很是多的靜態內容,每次都要參與遍歷就會很是浪費性能。
能夠看到vue3.0在生成虛擬DOM的時候,第二個 div 標籤爲綁定的變量,因此打上了 1 標籤,表明的是 TEXT(文字),從而會將內容分爲靜態資源和動態內容,從而更新的時候只diff動態的部分。
具體的請看源碼
咱們平時在開發過程當中寫函數的時候,定義一些寫死的變量時,都會將變量提高出去定義,Vue 3.0 在這方面也作了一樣的優化
這表明了這個變量只會被建立一次,然後只須要引用就行了,從而提高性能
默認狀況下 @click 事件被認爲是動態變量,因此每次更新視圖的時候都會追蹤它的變化。
可是正常狀況下,咱們的 @click 事件在視圖渲染前和渲染後,都是同一個事件,基本上不須要去追蹤它的變化,因此 Vue 3.0 對此做出了相應的優化叫事件監聽緩存。
因而可知, 設置了cacheHandler後,靜態標記爲8的的動態節點變成了靜態節點,從而不參與diff,提高了性能。
從字面意思來理解,Proxy對象是目標對象的一個代理器,任何對目標對象的操做(實例化,添加/刪除/修改屬性等等),都必須經過該代理器。所以咱們能夠把來自外界的全部操做進行攔截和過濾或者修改等操做。
引用大佬的例子來展現下Proxy對象的功能:
let foo = {
a:1,
b:2
}
let handler = {
set:(obj,key,value)=>{
console.log('set')
obj[key] = value
return true
}
}
let p = new Proxy(foo,handler)
p.a = 3 // 打印出console.log('set')
複製代碼
相信全部的前端面試的時候都被問過這個問題,vue的雙向數據綁定是怎麼實現的?
標準答案應該都差很少:
Vue實現數據雙向綁定主要利用的就是: 數據劫持和發佈訂閱模式。所謂數據劫持,就是利用JavaScript的訪問器屬性,即Object.defineProperty()方法,當對對象的屬性進行賦值時,Object.defineProperty就能夠經過set方法劫持到數據的變化,而後通知發佈者(主題對象)去通知全部觀察者,觀察者收到通知後,就會對視圖進行更新。
在Vue2.x中,使用Object.defineProperty()來實現響應式對象,對於一些複雜的對象,還須要循環遞歸的給每一個屬性增長上getter/setter監聽器,這使得組件的初始化很是耗時。vue3中,composition-api提供了一種建立響應式對象的方法reactive,其內部就是利用了Proxy API來實現的,這樣就能夠不用針對每一個屬性來一一進行添加,減小開銷提高性能。
vue3.0更新的核心功能除了上面的內容,還包括Tree shaking支持、以及對typescript的支持,以及Fragments、等等小的東西,固然還有最重要的vite,都是值得了解一下的。