官网地址:
vue3 与vue2的区别
1、性能
Vue3 通过使用 Proxy 对象来重写响应式系统,从而在渲染大型数据集时提高了性能。此外,Vue3 还引入了静态提升和
模板缓存等新特性,这些特性有助于减少渲染时间和提高性能。
2、API 设计
Vue3 中的 API 设计更加一致,使得使用 Vue 更加容易。例如,Vue3 中的 Composition API 将相关逻辑组合在一起,使
得组件更加可重用和易于维护。
3、包大小
Vue3 的包大小比 Vue2 小得多,这对于移动端和网络慢的用户来说尤其重要。
4、TypeScript 支持
Vue3 中对 TypeScript 提供了更好的支持,使得开发人员可以更轻松地编写类型安全的代码。
5、生命周期:
Vue3 中的生命周期钩子发生了变化,例如,beforeCreate 和 created 被合并成了一个新的生命周期钩子 beforeMount
**5、高可维护性 **
Vue 3 将带来更可维护的源代码。它不仅会使用 TypeScript,而且许多包被解耦,更加模块化。
正文
我们从官网上能看到vue3对于vue2迁移的新功能
然后我以做项目而言,为了能快速上手,会简单的介绍一下关于我们必须掌握的功能
生命周期
从图中我们可以看到 Vue3 新增了setup, 然后是将 Vue2 中的beforeDestroy名称变更成beforeUnmount; destroyed 表更为 unmounted,作者说这么变更纯粹是为了更加语义化,因为一个组件是一个mount和unmount的过程。其他 Vue2 中的生命周期仍然保留
每个生命周期的解释:
beforeCreate和created被setup替换了(但是 Vue3 中仍然可以使用, 因为 Vue3 是向下兼容的, 也就是实际使用的是 vue2 的)。
Composition API
reactive、ref 与 toRefs*
在 vue2.x 中, 定义数据都是在data中, 但是 Vue3.x 可以使用reactive和ref来进行数据定义。*
那么ref和reactive他们有什么区别呢?(reactive用于处理对象的双向绑定,但是不能代理基本类型,例如字符串、数字、boolean 等。ref也是可以定义对象的双向绑定)。* toRefs 用于将一个 reactive 对象转化为属性全部为 ref 对象的普通对象*
Setup
它是 vue3 中一个新的配置项,值为一个函数。所有的组合 api 都要在它里面使用。
setup 执行时机是在 beforeCreate 之前执行,详细的可以看后面生命周期讲解。
setup中不能访问 Vue2 中最常用的this对象
context中提供了this中最常用的三个属性:attrs、slot 和emit,分别对应 Vue2.x 中的 emit发射事件。并且这几个属性都是自动同步最新的值,所以我们每次使用拿到的都是最新值。
双向绑定: Object.defineProperty 与 Proxy
源码地址** : Src/core/observer/index.js
Object.defineProperty只能劫持对象的属性, 而 Proxy 是直接代理对象
由于Object.defineProperty只能劫持对象属性,需要遍历对象的每一个属性,如果属性值也是对象,就需要递归进行深度遍历。但是 Proxy 直接代理对象, 不需要遍历操作
Object.defineProperty对新增属性需要手动进行Observe
因为Object.defineProperty劫持的是对象的属性,所以新增属性时,需要重新遍历对象,对其新增属性再次使用Object.defineProperty进行劫持。也就是 Vue2.中给数组和对象新增属性时,需要使用set内部也是通过调用Object.defineProperty去处理的。
Teleport
例子:
在子组件Header中使用到Dialog组件,我们实际开发中经常会在类似的情形下使用到 Dialog ,此时Dialog就被渲染到一层层子组件内部,处理嵌套组件的定位、z-index和样式都变得困难。
Dialog从用户感知的层面,应该是一个独立的组件,从 dom 结构应该完全剥离 Vue 顶层组件挂载的 DOM;同时还可以使用到 Vue 组件内的状态(data或者props)的值。简单来说就是,即希望继续在组件内部使用Dialog, 又希望渲染的 DOM 结构不嵌套在组件的 DOM 中。
此时就需要 Teleport 上场,我们可以用包裹Dialog, 此时就建立了一个传送门,可以将Dialog渲染的内容传送到任何指定的地方。
接下来就举个小例子,看看 Teleport 的使用方式
v-model
v-model
可以在组件上使用以实现双向绑定。
首先让我们回忆一下 v-model
在原生元素上的用法:
<input v-model="searchText" />
在代码背后,模板编译器会对 v-model
进行更冗长的等价展开。因此上面的代码其实等价于下面这段:
<input
:value="searchText"
@input="searchText = $event.target.value"
/>
而当使用在一个组件上时,v-model
会被展开为如下的形式:
<CustomInput
:modelValue="searchText"
@update:modelValue="newValue => searchText = newValue"
/>
要让这个例子实际工作起来,<CustomInput>
组件内部需要做两件事:
- 将内部原生
<input>
元素的value
attribute 绑定到modelValue
prop - 当原生的
input
事件触发时,触发一个携带了新值的update:modelValue
自定义事件
这里是相应的代码:
<!-- CustomInput.vue -->
<script>
export default {
props: ['modelValue'],
emits: ['update:modelValue']
}
</script>
<template>
<input
:value="modelValue"
@input="$emit('update:modelValue', $event.target.value)"
/>
</template>
现在 v-model
可以在这个组件上正常工作了:
template
<CustomInput v-model="searchText" />
另一种在组件内实现 v-model
的方式是使用一个可写的,同时具有 getter 和 setter 的 computed
属性。get
方法需返回 modelValue
prop,而 set
方法需触发相应的事件:
vue
<!-- CustomInput.vue -->
<script>
export default {
props: ['modelValue'],
emits: ['update:modelValue'],
computed: {
value: {
get() {
return this.modelValue
},
set(value) {
this.$emit('update:modelValue', value)
}
}
}
}
</script>
<template>
<input v-model="value" />
</template>
v-model
的参数 #
默认情况下,v-model
在组件上都是使用 modelValue
作为 prop,并以 update:modelValue
作为对应的事件。我们可以通过给 v-model
指定一个参数来更改这些名字:
template
<MyComponent v-model:title="bookTitle" />
在这个例子中,子组件应声明一个 title
prop,并通过触发 update:title
事件更新父组件值:
vue
<!-- MyComponent.vue -->
<script>
export default {
props: ['title'],
emits: ['update:title']
}
</script>
<template>
<input
type="text"
:value="title"
@input="$emit('update:title', $event.target.value)"
/>
</template>
多个 v-model
绑定#
利用刚才在 v-model
参数小节中学到的指定参数与事件名的技巧,我们可以在单个组件实例上创建多个 v-model
双向绑定。
组件上的每一个 v-model
都会同步不同的 prop,而无需额外的选项:
template
<UserName
v-model:first-name="first"
v-model:last-name="last"
/>
vue
<script>
export default {
props: {
firstName: String,
lastName: String
},
emits: ['update:firstName', 'update:lastName']
}
</script>
<template>
<input
type="text"
:value="firstName"
@input="$emit('update:firstName', $event.target.value)"
/>
<input
type="text"
:value="lastName"
@input="$emit('update:lastName', $event.target.value)"
/>
</template>
处理 v-model
修饰符#
在学习输入绑定时,我们知道了 v-model
有一些内置的修饰符,例如 .trim
,.number
和 .lazy
。在某些场景下,你可能想要一个自定义组件的 v-model
支持自定义的修饰符。
我们来创建一个自定义的修饰符 capitalize
,它会自动将 v-model
绑定输入的字符串值第一个字母转为大写:
template
<MyComponent v-model.capitalize="myText" />
组件的 v-model
上所添加的修饰符,可以通过 modelModifiers
prop 在组件内访问到。在下面的组件中,我们声明了 modelModifiers
这个 prop,它的默认值是一个空对象:
vue
<script>
export default {
props: {
modelValue: String,
modelModifiers: {
default: () => ({})
}
},
emits: ['update:modelValue'],
created() {
console.log(this.modelModifiers) // { capitalize: true }
}
}
</script>
<template>
<input
type="text"
:value="modelValue"
@input="$emit('update:modelValue', $event.target.value)"
/>
</template>
注意这里组件的 modelModifiers
prop 包含了 capitalize
且其值为 true
,因为它在模板中的 v-model
绑定 v-model.capitalize="myText"
上被使用了。
有了这个 prop,我们就可以检查 modelModifiers
对象的键,并编写一个处理函数来改变抛出的值。在下面的代码里,我们就是在每次 <input />
元素触发 input
事件时将值的首字母大写:
vue
<script>
export default {
props: {
modelValue: String,
modelModifiers: {
default: () => ({})
}
},
emits: ['update:modelValue'],
methods: {
emitValue(e) {
let value = e.target.value
if (this.modelModifiers.capitalize) {
value = value.charAt(0).toUpperCase() + value.slice(1)
}
this.$emit('update:modelValue', value)
}
}
}
</script>
<template>
<input type="text" :value="modelValue" @input="emitValue" />
</template>
对于又有参数又有修饰符的 v-model
绑定,生成的 prop 名将是 arg + "Modifiers"
。举例来说:
template
<MyComponent v-model:title.capitalize="myText">
相应的声明应该是:
js
export default {
props: ['title', 'titleModifiers'],
emits: ['update:title'],
created() {
console.log(this.titleModifiers) // { capitalize: true }
}
}