vue3学习笔记

一、创建项目

  1. 使用 cli 创建
1
2
3
4
npm i -g @vue/cli
vue create <projectName>
cd projectName
npm run serve
  1. 使用vite创建

1
2
3
4
npm init vite-app <projectName>
cd <projectName>
npm i
npm run dev

学习时,使用的是 cli 创建的工程。

二、常用 Composition API

(一)、setup()

组件中用到的:数据、方法等均要配置到 setup 中

setup()中返回一个对象,对象中属性方法在模板中可直接使用。

vue2 不要与 vue3 混用,vue2 可以访问到 vue3 中的属性方法,但 vue3 中不能读取 vue2 中的属性方法。

setup()不能是 async 函数,返回值不为 return 的对象,而为 promise。

(二)、ref 函数

xxxxxxxxxx46 1#include

import {ref} from 'vue'

通过 ref 函数可以定义响应式数据

1
2
3
4
5
6
7
let name = ref("张三"); //生成refimpl实例对象
{
{
name;
}
} //插值语法
name.value; //函数内获取值

(三)、reactive 函数

定义对象类型响应式数据(基本类型不可用)

reactive 函数返回值是代理对象(Proxy 实例对象,简称 proxy 对象)

基于 ES6 的 Proxy 实现

1
2
3
4
let person = reactive({
name: "张三",
age: 18,
});

(四)、Vue3 响应式原理

  1. vue2 中实现原理

1
2
3
4
Object.defineProperty(person, "age", {
get() {},
set(value) {},
});

捕获不到删除与增加属性。

  1. vue3 中实现原理

    • Proxy:拦截对象中任意属性的变化,包括增删改查
    • Reflect:对被代理的对象进行操作
1
2
3
4
5
6
7
8
9
10
11
12
//Proxy:
const p = new Proxy(person, {
get(target, propName) {
return target[propname]; //读取了{propname}属性的值
},
set(target, propName, value) {
target[propName] = value; //修改了{propname}属性的值或增加了{propname}属性
},
deleteProperty(target, propName) {
return delete target[propName]; //删除了{propname}属性
},
});

其中 target 代表源数据,propName 代表调用的属性,value 代表传入的值。

1
2
3
4
5
6
7
let obj={
a:100,
b=200
}
Reflect.get(obj,'a') //获取obj的a值
Reflect.set(obj,'a',300) //设置obj的值为300
Reflect.deleteProperty(obj,'a') //删除a

Reflect 的函数均有返回值,代表操作是否成功。

汇总后可写为:

1
2
3
4
5
6
7
8
9
10
11
const p = new Proxy(person, {
get(target, propName) {
return Reflect.get(target, propName);
},
set(target, propName, value) {
return Reflect.set(target, propName, value);
},
deleteProperty(target, propName) {
return Reflect.deleteProperty(target.propName);
},
});

(五)、setup 注意点

  1. 执行时机比 beforeCreate 早

  2. setup 接受参数

1
setup(props,context){}
  • props 中包含组件外部传递过了,并且内部声明接受了的属性。

  • context 为上下文对象,context 中含有 3 个常用属性:

    • attrs:值为对象,包含组件外部传递过来,但没有在 props 中声明接收的属性。
    • slots:收到的插槽内容,相当于this.$slots
    • emit:分发自定义事件函数,相当于this.$emit

(六)、计算属性 computed

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import {computed} from 'vue'
export default{
setup(){
let fn = computed({ //完整形式
get(){},
set(value){}
})
let fn = computed(()=>{ //简写形式
})
}
return {
fn
}
}

(七)、监视属性 watch

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import {ref,reactive,watch} from 'vue'
export default{
setup()
{
let sum=ref(0);
let msg=ref(1);
let person=reactive({
name:"张三",
age:20
})
watch(sum,(new,old)=>{},{immediate:true}) //监视一个响应式数据
watch([sum,msg],(new,old)=>{},{immediate:true}) //监视多个响应式数据
watch(person,(new,old)=>{},{immediate:true}) //监视reactive对象,无法正确获取oldValue,无法关闭深度监视
watch(()=>person.name,(new,old)=>{}) //监视reactive对象中某个值
watch([()=>person.name,()=>person.age],(new,old)=>{}) //监视reactive对象中某个值
}
}

(八)、watchEffect

1
2
3
4
5
import {ref,reactive,watch,watchEffect} from 'vue'
setup(){
watchEffect(()=>{
})
}

watchEffect 会监视回调函数中所有被用到的属性。

(九)、生命周期

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import {onBeforeMount,onMounted,onBeforeUpdate,onUpdated,onBeforeUnmounted,onUnmounted} from 'vue'
setup(){
onBeforeMount(()={}) //组合式API
onBeforeMount(()={})
onBeforeUpdate(()={})
onUpdated(()={})
onBeforeUnmounted(()={})
onUnmounted(()={})
}
beforeCreate(){} //配置项形式
created(){}
beforeMount(){}
mounted(){}
beforeUpdate(){}
update(){}
beforeUnmount(){}
unmounted(){}

(十)、自定义 hook*

在 src 目录下创建 hooks 文件夹,文件通常命名为 usexxx.js。

1
2
3
4
5
6
7
8
9
10
11
12
//usexxx.js
import {
onBeforeMount,
onMounted,
onBeforeUpdate,
onUpdated,
onBeforeUnmounted,
onUnmounted,
} from "vue";
export default function () {
//将某一功能的所有数据、方法、生命周期、监视同一放在一个hook里,使功能更有序。
}
1
2
3
4
5
6
7
8
//组件
import usexxx.js from '../hooks/usexxx'
export default{
setup(){
const u = usexxx()
return {u}
}
}

hook 本质是一个函数,把 setup 函数中的 Composition API 进行封装,实现功能复用

(十一)、toRef 与 toRefs

toRef 创建一个 ref 对象,并将自身的值指向另一个对象中的某个属性

1
2
3
4
5
6
7
8
9
10
11
12
13
let person = reactive({
name:'name',
age:'age',
kids:{
tom:{
age:20;
}
}
})
const name = toRef(person,'name')
return {
...toRefs(person)
}

响应式数据中的某个属性单独提供给外部使用。

toRefs 是 toRef 的扩展,可批量创建多个 ref。

const name = toRef(person)

详见:https://www.bilibili.com/video/BV1Zy4y1K7SH?p=157

三、其他 Composition API

(一)、shallowReactive 与 shallowRef

shallowReactive 只处理对象最外层属性的响应式(浅响应式)

shallowRef 只处理基本数据类型响应式,不处理对象响应式

(二)、readonly 与 shallowReadonly

readonly 能让响应式数据变为只读(深只读)

shallowReadonly 让响应式数据变为只读(浅只读)

(三)、toRaw 与 markRaw

toRaw 将由reactive生成的响应式对象转为普通对象。

markRaw 将标记一个对象,使其永远不会成为响应式对象。

(四)、customRef

创建自定义 Ref。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import {customRef} from 'vue'
setup(){
let word = myRef('hello')
function myRef(value){
return customRef((track,trigger)=>{
return{
get(){
track() //追踪数据变化
return value;
},
set(new){
value = new
trigger() //重新解析模板
}
}
})
}
}

(五)、provide 与 inject

适用于祖与后代组件间通信

1
2
3
4
5
6
7
8
9
10
11
12
//组组件
import { provide, reactive } from "vue";
export default {
setup() {
let person = reactive({
name: "张三",
age: 20,
});
provide("person", person);
return { ...toRefs(person) };
},
};
1
2
3
4
5
6
7
import { inject } from "vue";
export default {
setup() {
let person = inject("person");
return { ...toRefs(person) };
},
};

(六)、响应式数据判断

  • isRef:判断是否为 ref 对象

  • isReactive:判断是否为 reactive 创建的代理对象

  • isReadonly:判断是否为 readonly 创建的只读代理对象

  • isProxy:判断是否为 reactive 或 readonly 创建的代理对象

四、新组件

(一)、Fragment

组件可以没有根标签,内部多个标签会包含在一个 Fragment 虚拟元素中。

(二)、Teleport

将组件 html 解构传送到指定解构

1
2
3
4
5
<teleport to="移动位置">
<div v-if="show">
<div>内容</div>
</div>
</teleport>

移动位置可以是 id,class,标签名

(三)、Suspense

1
2
import { defineAsyncComponent } from "vue";
const Child = defineAsyncComponent(() => import("./components/Child")); //异步引入
1
2
3
4
5
6
7
8
9
10
<Suspense>
<template v-slot:default>
//组件加载完成后显示
<Child></Child>
</template>
<template v-slot:fallback>
//组件加载中显示
<h3>加载中</h3>
</template>
</Suspense>

使用异步加载后,子组件可以 setup 可以使用异步加载模式返回 Promise 对象

五、全局 API 转移

image-20220724233205931

来源:https://www.bilibili.com/video/BV1Zy4y1K7SH?p=168

Vue3 中移除 v-on.native 修饰符

取而代之是在子组件中添加emits:[]属性来申明自定义事件,不声明默认为原生事件

1
2
<!--父组件-->
<components v-on:close="close" v-on:click="click"></components>
1
2
3
4
//子组件
export default {
emits: ["close"], //此时v-on:close为自定义事件而v-on:click为原生事件
};

Vue3 中移除了过滤器,通过 computed 替代