Vue3 笔记

168 阅读4分钟

cn.vuejs.org/api/composi…

一、基础

1.扩展全局属性

image.png 内置的全局属性有以下这些

image.png

因此,我们可以直接在模板中使用

image.png

如果想要扩展全局属性,在main.js中,将自定义变量挂载globalProperties中,然后就可以在任意组件中进行使用了

image.png

image.png

2.内置指令

v-show 切换display:block|none来实现切换
v-memo 类似react usememo

3.响应式基础

3.1 ref

在模板中使用 ref 时,需要附加 .value。为了方便起见,当在模板中使用时,ref 会自动解包(在模板渲染上下文中,只有顶级的 ref 属性才会被解包。)

可以通过 shallow ref 来放弃深层响应性。对于浅层 ref,只有 .value 的访问会被追踪。浅层 ref 可以用于避免对大型数据的响应性开销来优化性能、或者有外部库管理其内部状态的情况。

image.png

3.2 reactive

reactive() 的局限性

reactive() API 有一些局限性:

  1. 有限的值类型:它只能用于对象类型 (对象、数组和如 MapSet 这样的集合类型)。它不能持有如 stringnumber 或 boolean 这样的原始类型
  2. 不能替换整个对象:由于 Vue 的响应式跟踪是通过属性访问实现的,因此我们必须始终保持对响应式对象的相同引用。这意味着我们不能轻易地“替换”响应式对象,因为这样的话与第一个引用的响应性连接将丢失:
  3. 对解构操作不友好:当我们将响应式对象的原始类型属性解构为本地变量时,或者将该属性传递给函数时,我们将丢失响应性连接:

ref的解包特性感觉要分好多种情况,有时候有有时候不行,😄感觉只要涉及到ref的都用value去取值是最保险的,而且容易区分reactive

4.计算属性

  1. 计算属性的返回值是ref对象,但因为和ref一样,存在解包特性,所以在模板中使用时,不需要带上value
  2. 我们经常说,computed和methods的区别是,computed有缓存,但是其只是对响应式依赖有缓存!!!,同理,watch也是只监听响应式数据

image.png

5.v-for

使用in和of均可

image.png 遍历对象时

const myObject = reactive({
    title: 'How to do lists in Vue',
    author: 'Jane Doe',
    publishedAt: '2016-04-10'
})

<li v-for="(value, key, index) in myObject">
    {{ index }}. {{ key }}: {{ value }}
</li>

v-if和v-for不能同时使用

image.png

6.v-on

模板编译器会通过检查 v-on 的值是否是合法的 JavaScript 标识符或属性访问路径来断定是何种形式的事件处理器。举例来说,foofoo.bar 和 foo['bar'] 会被视为方法事件处理器,而 foo() 和 count++ 会被视为内联事件处理器

// 在内联处理器中调用方法
<button @click="say('hello')">Say hello</button>
// 方法事件处理器
<button @click="say">Say hello</button>

image.png

事件修饰符

cn.vuejs.org/guide/essen…

生命周期

cn.vuejs.org/guide/essen…

二、API

1、组合式API

1.1、setup()

setup第一个参数是props,props是响应式的,不能解构; image.png 第二个参数是context,context中包含的attrs, slots, emit, expose是非响应式的,可以解构 image.png

1.2 computed

computed返回的是一个ref对象,通常是只读的,但是可以通过set,get的方式,使其可写

image.png

1.3 readonly

接受一个对象 (不论是响应式还是普通的) 或是一个 ref,返回一个原值的只读代理

<script setup>
import { ref, readonly } from 'vue';
const userAge = ref(23);
const myAge = readonly(userAge);

const handleAdd = () => {
  // userAge.value++; myAge.value会变
  myAge.value++; myAge.value值不变
};
</script>

<template>
  <div class="card">
    <button @click="handleAdd">add</button>
    <p>我的年龄是{{ myAge }}</p>
  </div>
</template>

<style scoped>
.read-the-docs {
  color: #888;
}
</style>

1.4 toRef()

基于响应式对象上的一个属性,创建一个对应的 ref。这样创建的 ref 与其源属性保持同步:改变源属性的值将更新 ref 的值,反之亦然

const state = reactive({
  foo: 1,
  bar: 2
})

// 双向 ref,会与源属性同步
const fooRef = toRef(state, 'foo')

// 更改该 ref 会更新源属性
fooRef.value++
console.log(state.foo) // 2

// 更改源属性也会更新该 ref
state.foo++
console.log(fooRef.value) // 3

1.5 toRefs()

将一个响应式对象转换为一个普通对象,这个普通对象的每个属性都是指向源对象相应属性的 ref。每个单独的 ref 都是使用 toRef() 创建的

const state = reactive({
  foo: 1,
  bar: 2
})

const stateAsRefs = toRefs(state)
/*
stateAsRefs 的类型:{
  foo: Ref<number>,
  bar: Ref<number>
}
*/

// 这个 ref 和源属性已经“链接上了”
state.foo++
console.log(stateAsRefs.foo.value) // 2

stateAsRefs.foo.value++
console.log(state.foo) // 3

1.6 toRaw()

根据一个 Vue 创建的代理返回其原始对象

const foo = {}
const reactiveFoo = reactive(foo)

console.log(toRaw(reactiveFoo) === foo) // true

toRaw() 可以返回由 reactive()readonly()shallowReactive() 或者 shallowReadonly() 创建的代理对应的原始对象。

tips: 一定要注意,曾经花了一个晚上排查,最终发现问题出现在toRaw上面,使用toRaw返回的对象不是响应式的,后续的更改不会修改其响应式对象,所以追踪不到最新值!!!

1.7 markRaw()

将一个对象标记为不可被转为代理。返回该对象本身。

1.8 provide()