Vue3 与 Vue2 官方文档解读

本文深入探讨Vue3的新特性,包括MVVM、组合式API、响应式系统、ref与reactive的区别与应用、模板引用、计算属性与方法的对比、组件注册与事件处理。此外,还涵盖了生命周期、异步组件、过渡效果、插槽和自定义指令的使用,以及性能优化策略。通过对Vue3的全面解析,助你提升开发效率。
摘要由CSDN通过智能技术生成

MVVM

M(model)对应data里的数据;V对应模版;VM对应vue的实例,通过数据绑定与事件监听实现vue实例

Object.defineProperty

vue通过defineProperty把data对象的所有属性添加到vm上再为每一个属性指定一个getter和setter负责读写date中对应的属性,实现数据响应式

let person = {
   
	name: 'zc', sex: 'man'
}
枚举person
Object.keys(person)

let input = 18
Object.defineProperty(person, 'age', {
   
	// value: 13,
	// enumerable: true, 控制属性可枚举 默认false
	// writable:true 控制属性是否被修改 默认false
	// configurable: true 控制是否可以删除 默认false
	get() {
   
		return input	
	}
	set(value) {
   
		input = value
	}
})

单文件组件 缩写为 SFC

Vue 的单文件组件会将一个组件的逻辑 (JavaScript),模板 (HTML) 和样式 (CSS) 封装在同一个文件里

选项式 API (Options API)

例如 data、methods 和 mounted。选项所定义的属性都会暴露在函数内部的 this 上,它会指向当前的组件实例。

组合式 API (Composition API)

组合式 API 通常会与 script setup 搭配使用,告诉 Vue 需要在编译时进行一些处理,让我们可以更简洁地使用组合式 API

选项式 API 与 组合式 API

  • 实际上,选项式 API 是在组合式 API 的基础上实现的!
  • 选项式 API 以“组件实例”的概念为中心 (即上述例子中的 this),选项式 API 需要依赖 this 上下文对象访问属性
  • 组合式 API 的核心思想是直接在函数作用域内定义响应式状态变量,并将从多个函数中得到的状态组合起来处理复杂问题
  • compositionApi对tree-shaking更友好代码也容易压缩,通过组合函数来实现更加简洁高效的逻辑复用,解决了 mixins 的所有缺陷

Attribute 绑定

<div :id="`list-${id}`"></div>

DOM 更新时机

nextTick,访问更新后的 DOM

import {
    nextTick } from 'vue'

function increment() {
   
  state.count++
  nextTick(() => {
   
    // 访问更新后的 DOM
  })
}

响应式对象

响应式对象其实是 JavaScript Proxy,其行为表现与一般对象相似。不同之处在于 Vue 能够跟踪对响应式对象属性的访问与更改操作

依据官方文档推荐使用reactive定义对象

import {
    reactive } from 'vue'

const obj = reactive({
   
  nested: {
    count: 0 },
  arr: ['foo', 'bar']
})

function mutateDeeply() {
   
  // 以下都会按照期望工作
  obj.nested.count++
  obj.arr.push('baz')
}

在 setup() 函数中手动暴露大量的状态和方法非常繁琐。幸运的是,我们可以通过使用构建工具来简化该操作。当使用单文件组件(SFC)时,我们可以使用

ref 和 reactive

ref 用来定义:基本类型数据。
reactive 用来定义:对象(或数组)类型数据。
ref 也可以用来定义对象(或数组)类型数据, 它内部会自动通过reactive转为代理对象。
从原理角度对比
ref 通过Object.defineProperty()的get与set来实现响应式(数据劫持)。
reactive 通过使用 Proxy 来实现响应式(数据劫持), 并通过 Reflect 操作源对象内部的数据。

响应式代理 vs. 原始对象

reactive() 返回的是一个原始对象的 Proxy,它和原始对象是不相等的。

const raw = {
   }
const proxy = reactive(raw)
代理对象和原始对象不是全等的
console.log(proxy === raw) // false
在同一个对象上调用 reactive() 会返回相同的代理
console.log(reactive(raw) === proxy) // true
在一个代理上调用 reactive() 会返回它自己
console.log(reactive(proxy) === proxy) // true
这个规则对嵌套对象也适用。依靠深层响应性,响应式对象内的嵌套对象依然是代理
const proxy = reactive({
   })
const raw = {
   }
proxy.nested = raw
console.log(proxy.nested === raw) // false

reactive() 的局限性

  1. 仅对对象类型有效(对象、数组和 Map、Set 这样的集合类型),而对 string、number 和 boolean 这样的 原始类型 无效。因为 Vue 的响应式系统是通过属性访问进行追踪的,因此我们必须始终保持对该响应式对象的相同引用
  2. 这意味着我们不可以随意地“替换”一个响应式对象,也意味着当我们将响应式对象的属性赋值或解构至本地变量时,或是将该属性传入一个函数时,我们会失去响应性
let state = reactive({
    count: 0 })
上面的引用 ({
    count: 0 }) 将不再被追踪(响应性连接已丢失!)
state = reactive({
    count: 1 })

**我们将响应式对象的属性赋值或解构至本地变量时,或是将该属性传入一个函数时,我们会失去响应性 **

const state = reactive({
    count: 0 })
count 也和 state.count 失去了响应性连接
let {
    count } = state
不会影响原始的 state
count++

该函数接收一个普通数字,并且
将无法跟踪 state.count 的变化
callSomeFunction(state.count)

用 ref() 定义响应式变量

Vue 提供了一个 ref() 方法来允许我们创建可以使用任何值类型的响应式 ref:ref() 让我们能创造一种对任意值的 “引用”,并能够在不丢失响应性的前提下传递这些引用

ref() 将传入参数的值包装为一个带 .value 属性的 ref 对象:

const count = ref(0)
console.log(count) // { value: 0 }
console.log(count.value) // 0

count.value++
console.log(count.value) // 1

当值为对象类型时,会用 reactive() 自动转换它的 .value

const objectRef = ref({
    count: 0 })
这是响应式的替换
objectRef.value = {
    count: 1 }

ref实际应用dome

ref 被传递给函数或是从一般对象上被解构时,不会丢失响应性:

const obj = {
   
  foo: ref(1),
  bar: ref(2)
}
该函数接收一个 ref
需要通过 .value 取值
但它会保持响应性
callSomeFunction(obj.foo)
仍然是响应式的
const {
    foo, bar } = obj

例如, object 是顶层属性,但 object.foo 不是。
渲染的结果会是一个 [object Object]1
现在渲染结果将是 2。

const object = {
    foo: ref(1) }
{
   {
    object.foo + 1 }} //[object Object]1
仍然是响应式的,同上的实例
const {
    foo } = object
{
   {
    foo + 1 }} // 2

正常不会出现{ { object.foo + 1 }}的运算,在html模版中直接使用,不需要解构也可以

{
   {
    object.foo }}

ref 在响应式对象中的解包

const count = ref(0)
const state = reactive({
   
  count
})
state.count = 1
console.log(count.value) // 1

如果将一个新的 ref 赋值给一个关联了已有 ref 的属性,那么它会替换掉旧的 ref:

const otherCount = ref(2)

state.count = otherCount
console.log(state.count) // 2
// 原始 ref 现在已经和 state.count 失去联系
console.log(count.value) // 1

数组和集合类型的 ref 解包

  1. 跟响应式对象不同,当 ref 作为响应式数组或像 Map 这种原生集合类型的元素被访问时,不会进行解包。
const books = reactive([ref('Vue 3 Guide')])
// 这里需要 .value
console.log(books[0].value)

const map = reactive(new Map([['count', ref(0)]]))
// 这里需要 .value
console.log(map.get('count').value)

计算属性缓存 vs 方法

  1. 计算属性值会基于其响应式依赖被缓存。一个计算属性仅会在其响应式依赖更新时才重新计算。这意味着只要 响应式依赖 不改变,无论多少次访问 都会立即返回先前的计算结果
  2. 方法调用总是会在重渲染发生时再次执行函数,需要循环一个巨大的数组并做许多计算逻辑,并且可能也有其他计算属性依赖于 list。没有缓存的话,我们会重复执行非常多次

在计算属性中使用 reverse() 和 sort() 的时候务必小心!这两个方法将变更原始数组,计算函数中不应该这么做。请在调用这些方法之前创建一个原数组的副本:

- return numbers.reverse()
+ return [...numbers].reverse()

Class 与 Style 绑定

绑定一个返回对象的计算属性。这是一个常见且很有用的技巧

const isActive = ref(true)
const error = ref(null)

const classObject = computed(() => ({
   
  active: isActive.value && !error.value,
  'text-danger': error.value && error.value.type === 'fatal'
}))

v-if vs. v-show

  1. v-if 也是惰性的:如果在初次渲染时条件值为 false,则不会做任何事。条件区块只有当条件首次变为 true 时才被渲染。
  2. v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要频繁切换,则使用 v-show 较好;如果在运行时绑定条件很少改变,则 v-if 会更合适。

<//template> 上的 v-if 实际应用dome

v-else 和 v-else-if 也可以在 上使用。v-show 不支持在 元素上使用

<template v-if="ok">
  <h1>Title</h1>
  <p>Paragraph 1</p>
  <p>Paragraph 2</p>
</template>

列表渲染

建议使用ref申明数组,reactive申明对象,来源于官方文档推荐

v-for 与数组
const items = ref([{
    message: 'Foo' }, {
    message: 'Bar' }])
<li v-for="item in items">
  {
   {
    item.message }}
</li>
可以解构,是一种实用的技巧
<li v-for="({ message }, index) in items">
  {
   {
    message }} {
   {
    index }}
</li>
v-for 与对象
const myObject = reactive({
   
  title: 'How to do lists in Vue',
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值