
Vue3 vs Vue2
vue3
ref用于定义基本类型和引用类型,reactive仅用于定义引用类型
reactive只能用于定义引用数据类型的原因在于内部是通过ES6的Proxy实现响应式的,而Proxy不适用于基本数据类型
ref定义对象时,底层会通过reactive转换成具有深层次的响应式对象,所以ref本质上是reactive的再封装
ref
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
|
class RefImpl<T> { public dep: Dep private _value public _rawValue public __V_IS_REF: boolean = true constructor(value: T) { this._rawValue = value this._value = convert(value) this.dep = new Set() } get value() { trackRefValue(this) return this._value } set value(newValue) { if (!hasChanged(newValue, this._rawValue)) return this._value = convert(newValue) this._rawValue = newValue triggerEffects(this.dep) } }
export function ref<T>(value: T) { return new RefImpl(value) }
|
Vue3 vs Vue2
优势
组合式API:
- 更好的逻辑复用
- 更灵活的代码组织
- 更好的类型推导
- 更小的生产包体积
组合式API
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <script setup> import { ref, onMounted } from 'vue'
const count = ref(0)
function increment() { count.value++ }
onMounted(() => { console.log(`计数器初始值为 ${count.value}。`) }) </script>
<template> <button @click="increment">点击了:{{ count }} 次</button> </template>
|
全局API
1 2 3 4
| import { createApp } from 'vue'
const app = createApp({})
|
| 2.x 全局 API | 3.x 实例 API (app) |
|---|
| Vue.config | app.config |
| Vue.config.productionTip | 移除 (见下方) |
| Vue.config.ignoredElements | app.config.compilerOptions.isCustomElement (见下方) |
| Vue.component | app.component |
| Vue.directive | app.directive |
| Vue.mixin | app.mixin |
| Vue.use | app.use (见下方) |
| Vue.prototype | app.config.globalProperties (见下方) |
| Vue.extend | 移除 (见下方) |
Treeshaking
1 2 3 4 5 6
| import { nextTick } from 'vue'
nextTick(() => { // 一些和 DOM 有关的东西 })
|
v-model 和 sync
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| // vue2 <ChildComponent v-model="pageTitle" />
<ChildComponent :value="pageTitle" @input="pageTitle = $event" />
<ChildComponent :title="pageTitle" @update:title="pageTitle = $event" /> <ChildComponent :title.sync="pageTitle" />
// vue3 <ChildComponent v-model="pageTitle" />
<ChildComponent :modelValue="pageTitle" @update:modelValue="pageTitle = $event" />
|
key
1 2 3 4 5 6 7 8 9 10 11
| <template v-for="item in list"> <div :key="'heading-' + item.id">...</div> <span :key="'content-' + item.id">...</span> </template>
<template v-for="item in list" :key="item.id"> <div>...</div> <span>...</span> </template>
|
v-if,v-for
2.x 版本中在一个元素上同时使用 v-if 和 v-for 时,v-for 会优先作用。
3.x 版本中 v-if 总是优先于 v-for 生效。
响应式原理
Vue 2 使用 getter / setters 完全是出于支持旧版本浏览器的限制。而在 Vue 3 中则使用了 Proxy 来创建响应式对象,仅将 getter / setter 用于 ref。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| function reactive(obj) { return new Proxy(obj, { get(target, key) { track(target, key) return target[key] }, set(target, key, value) { target[key] = value trigger(target, key) } }) }
function ref(value) { const refObject = { get value() { track(refObject, 'value') return value }, set value(newValue) { value = newValue trigger(refObject, 'value') } } return refObject }
|
track收集依赖,trigger触发更新
vue2
生命周期
在Vue中,父子组件的生命周期执行顺序遵循以下规则:
- 父组件 beforeCreate
- 父组件 created
- 父组件 beforeMount
- 子组件 beforeCreate
- 子组件 created
- 子组件 beforeMount
- 子组件 mounted
- 父组件 mounted
更新过程中:
- 父组件 beforeUpdate
- 子组件 beforeUpdate
- 子组件 updated
- 父组件 updated
销毁过程中:
- 父组件 beforeDestroy
- 子组件 beforeDestroy
- 子组件 destroyed
- 父组件 destroyed
![Vue 实例生命周期]()
provide/inject
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| provide() { return { getBeCascaded: () => this.beCascaded }; },
inject: ['beCascaded'] computed: { beCascaded() { return this.beCascaded(); } }
this.beCascaded
provide() { return { obj: { beCascaded: this.beCascaded } }; } inject: ['obj']
this.obj.beCascaded
|