Vue3 学习

91 阅读6分钟

官网地址:

vuejs.org/guide/extra…

vue3 与vue2的区别

1、性能

Vue3 通过使用 Proxy 对象来重写响应式系统,从而在渲染大型数据集时提高了性能。此外,Vue3 还引入了静态提升和

模板缓存等新特性,这些特性有助于减少渲染时间和提高性能。

image.png

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迁移的新功能

image.png

然后我以做项目而言,为了能快速上手,会简单的介绍一下关于我们必须掌握的功能

生命周期

image.png

从图中我们可以看到 Vue3 新增了setup, 然后是将 Vue2 中的beforeDestroy名称变更成beforeUnmount; destroyed 表更为 unmounted,作者说这么变更纯粹是为了更加语义化,因为一个组件是一个mount和unmount的过程。其他 Vue2 中的生命周期仍然保留

image.png

每个生命周期的解释: image.png

beforeCreate和created被setup替换了(但是 Vue3 中仍然可以使用, 因为 Vue3 是向下兼容的, 也就是实际使用的是 vue2 的)。

Composition API

image.png

image.png

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对象

 

image.png

image.png context中提供了this中最常用的三个属性:attrs、slot 和emit,分别对应 Vue2.x 中的 attr属性、slot插槽和attr属性、slot插槽 和emit发射事件。并且这几个属性都是自动同步最新的值,所以我们每次使用拿到的都是最新值。

双向绑定: Object.defineProperty 与 Proxy

源码地址** : Src/core/observer/index.js

Object.defineProperty只能劫持对象的属性, 而 Proxy 是直接代理对象

由于Object.defineProperty只能劫持对象属性,需要遍历对象的每一个属性,如果属性值也是对象,就需要递归进行深度遍历。但是 Proxy 直接代理对象, 不需要遍历操作

Object.defineProperty对新增属性需要手动进行Observe

因为Object.defineProperty劫持的是对象的属性,所以新增属性时,需要重新遍历对象,对其新增属性再次使用Object.defineProperty进行劫持。也就是 Vue2.中给数组和对象新增属性时,需要使用set才能保证新增的属性也是响应式的,set才能保证新增的属性也是响应式的, set内部也是通过调用Object.defineProperty去处理的。

Teleport

例子:

在子组件Header中使用到Dialog组件,我们实际开发中经常会在类似的情形下使用到 Dialog ,此时Dialog就被渲染到一层层子组件内部,处理嵌套组件的定位、z-index和样式都变得困难。

Dialog从用户感知的层面,应该是一个独立的组件,从 dom 结构应该完全剥离 Vue 顶层组件挂载的 DOM;同时还可以使用到 Vue 组件内的状态(data或者props)的值。简单来说就是,即希望继续在组件内部使用Dialog, 又希望渲染的 DOM 结构不嵌套在组件的 DOM 中。

此时就需要 Teleport 上场,我们可以用包裹Dialog, 此时就建立了一个传送门,可以将Dialog渲染的内容传送到任何指定的地方。

接下来就举个小例子,看看 Teleport 的使用方式

image.png

image.png

image.png

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> 组件内部需要做两件事:

  1. 将内部原生 <input> 元素的 value attribute 绑定到 modelValue prop
  2. 当原生的 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 }
  }
}