API
和內置組件/功能支持tree-shaking
10kb gzipped
上下Vue
更快(性能優化)Proxy
的響應式實現,性能總體優於Object.defineProperty
長遠來看,JS
引擎會繼續優化Proxy
,但Object.defineProperty
(getter/setter
)基本不會再有針對性的優化html
React 解決方法: 時間分片vue
經過模板靜態分享生成更優化的VDOM渲染函數node
先將模板切分爲block,每一個block內部動態節點位置都是固定的npm
每一個block的根節點會記錄本身所包含的動態節點(包含子block的根節點)編程
更新時,只須要直接遍歷動態節點api
block Tree 數組
最簡單狀況 性能優化
v-if狀況 架構
優化效果app
單個函數內部的變量會被壓縮,對壓縮更友好
官方提供了一個vue-function-api依賴庫,以便vue2.x也可使用function api編程,不過它只有Function-based API的setup、value、computed、watch、lifecycle、provide、inject等部分API
// npm install vue-function-api --save
// 在2.x中使用
import Vue from 'vue'
import { plugin } from 'vue-function-api'
Vue.use(plugin)
複製代碼
是Function-Based API的入口函數,相似data(),setup()的返回值就是注入頁面模板的變量,能夠像data同樣直接使用
import { value } from 'vue'
function useMousePosition() { // 組件內容複用 Composition Function
const x = value(0) const y = value(0) const update = e => {
x.value = e.pageX
y.value = e.pageY
}
onMounted(() => {
window.addEventListener('mousemove', update)
})
onUnmounted(() => {
window.removeEventListener('mousemove', update)
})
return { x, y }
}
const MyComponent = {
setup(props) {
const msg = value('hello')
const {x, y} = useMousePosition()
const appendName = () => {
msg.value = `hello ${props.name}`
}
return {
msg,
appendName
}
},
template: `<div @click="appendName">{{ msg }}</div>`
}
複製代碼
import { value, createElement as h } from 'vue'
const MyComponent = {
setup(initialProps) {
const count = value(0)
const increment = () => { count.value++ }
return (props, slots, attrs, vnode) => (
h('button', {
onClick: increment
}, count.value)
)
}
}
複製代碼
一個包裝對象只有一個屬性.value,指向內部被包裝的值,該值能夠被修改
爲何要使用
Value Unwrapping(包裝對象的自動展開)
const MyComponent = {
setup() {
return {
count: value(0)
}
},
template: `<button @click="count++">{{ count }}</button>`
}
複製代碼
全部現有的生命週期鉤子都會有對應的 onXXX 函數(只能在 setup() 中使用):
import { onMounted, onUpdated, onUnmounted } from 'vue'
const MyComponent = {
setup() {
onMounted(() => {
console.log('mounted!')
})
onUpdated(() => {
console.log('updated!')
})
// destroyed 調整爲 unmounted
onUnmounted(() => {
console.log('unmounted!')
})
}
}
複製代碼
計算值的行爲跟計算屬性 (computed property) 同樣:只有當依賴變化的時候它纔會被從新計算。 computed(getter, setter) 返回的是一個只讀的包裝對象,它能夠和普通的包裝對象同樣在 setup() 中被返回 ,也同樣會在渲染上下文中被自動展開。默認狀況下,若是用戶試圖去修改一個只讀包裝對象,會觸發警告
import { value, computed } from 'vue'
const count = value(0)
const countPlusOne = computed(() => count.value + 1)
console.log(countPlusOne.value) // 1
count.value++
console.log(countPlusOne.value) // 2
複製代碼
// double 是一個計算包裝對象
const double = computed(() => count.value * 2)
watch(double, value => {
console.log('double the count is: ', value)
}) // -> double the count is: 0
count.value++ // -> double the count is: 2
複製代碼
const stop = watch(...)
// stop watching
stop()
// 若是 watch() 是在一個組件的 setup() 或是生命週期函數中被調用的,那麼該 watcher 會在當前組件被銷燬時也一同被自動中止:
export default {
setup() {
// 組件銷燬時也會被自動中止
watch(/* ... */)
}
}
複製代碼
3.0 的 props 選項不是必須的,若是你不須要運行時的 props 類型檢查,你也能夠選擇徹底在 TypeScript 的類型層面聲明 props 的類型:
import { createComponent, createElement as h } from 'vue'
interface Props {
msg: string
}
const MyComponent = createComponent({
setup(props: Props) {
return () => h('div', props.msg)
}
})
複製代碼
createComponent 從概念上來講和 2.x 的 Vue.extend 是同樣的,但在 3.0 中它實際上是單純爲了類型推導而存在的,內部實現是個 noop(直接返回參數自己)。它的返回類型能夠用於 TSX 和 Vetur 的模版自動補全。若是你使用單文件組件,則 Vetur 能夠自動隱式地幫你添加這個調用
import { createComponent } from 'vue'
const MyComponent = createComponent({
// props declarations are used to infer prop types
props: {
msg: String
},
setup(props) {
props.msg // string | undefined
// bindings returned from setup() can be used for type inference
// in templates
const count = value(0)
return {
count
}
}
})
複製代碼