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
}
}
})
复制代码