# vue3-test **Repository Path**: czw1474591391/vue3-test ## Basic Information - **Project Name**: vue3-test - **Description**: vue3-test 学习3新的api - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2022-03-20 - **Last Updated**: 2022-07-01 ## Categories & Tags **Categories**: Uncategorized **Tags**: vue3基础学习 ## README ##

一、常用 composition API

#### 1.setup 1. vue3.0 中的一个新配置项、值为一个函数 2. setup 是所有 composition Api 表演的舞台 3. 组件中所用到的数据、方法等等 均要配置在 setup 中 4. setup 函数两种返回值: - 若返回一个对象、则对象中的属性与方法可以在模板中直接使用 - 若返回一个渲染函数 则可以自定义渲染内容 5. 注意点: - vue2.x 中可以访问到 setup 中的属性和方法 - 但在 setup 中不能访问到 vue2 中的配置,如果有重名 setup 优先 - setup 不能是一个 async 函数 因为返回值不再是 return 的对象、而是 promise ###

setup 参数以及注意点

- setup 的执行时机 -

在 beforeCreate 之前执行一次,this 是 undefined

- setup 的参数 - props:值为对象,包含组件外部传递过来的,且组件内部声明接受了的属性 - context :上下文对象 - attrs:值为对象,包含组件外部传递过来,但没有在 props 中声明的属性,相当于` this.$attrs` - slots: 收到的插槽内容,父级更换为`v-slot:xxx`指令、相当于`this.$slots` - emit: 分发自定义事件的函数、相当于`this.$emit` ###

ref 函数

- 作用:定义一个响应式数据 - 语法: ```javascript const xxx = ref(initValue); ``` - 创建一个包含响应式数据的引用对象(referebce 对象 简称 ref 对象) - JS 中操作数据需要通过.value 属性 - 模板中读取数据不需要 value 属性 ####

reactive 函数

- 作用:定义一个引用类型的响应式数据,基本类型用 ref - 语法: ```javascript const xxx = reactive(Array || Object); ``` - reactive 定义的响应式数据是深层次的 - 内部基于 ES6 的 proxy 实现、通过代理对象操作源对象内部数据进行操作 ####

toRef 函数

- 作用:创建一个 ref 对象,其 value 值指向另一个对象的某个属性 - 语法:`const name = toRef(person,'name')` - 应用:要将响应式对象中的某个属性单独提供给外部使用(重新赋值给其他变量) - 扩展:`toRef`与`torefs`功能一致,但是可以创建多个 ref 对象,语法`toRefs(person)` 示例: ```javascript const person1 = reactive({ name: '张三', age: 15 }); const name = person1.name; //单独提供出去,会丢失响应式 ``` 正确使用 ```javascript const person1 = reactive({ name: '张三', age: 15 }); const name = toRef(person1, 'name'); // 导出单个ref对象 const { age } = toRefs(person1); // 批量导出多个ref对象,可以解构 ``` ####

shallowReactive 与 shallowRef 函数

- `shallowReactive`:只处理对象最外层的响应式,非 `proxy` 递归监听(浅响应式) - `shallowRef`:只处理基本数据烈性的响应式,不进行对象的响应式处理,(可手动触发 `triggerRef` 更新 ref 对象) - 使用场景: - 如果有一个对象数据,结构很深,但变化时只是最外层属性变化===>`shallowReactive` - 如果有一个对象数据,后续不会修改对象的属性,而是生新的对象进行替代 ===> `shallowRef` ```javascript ``` ####

toRef 与 markRaw 函数

- `toRef`函数是将被 ref 或 reactive 所代理的对象转换成普通对象 - `markRaw`函数是告诉 vue 不代理此对象 ```javascript const obj = { name: '张三', job: { age: 1 } }; const obj2 = markRaw(obj); // markRaw是告诉vue这个对象不被proxy所代理 const person2 = reactive(obj2); const person = reactive(obj); const person1 = toRaw(person); // toRaw是将ref或reactive对象转换成普通对象 console.log(person1); // 结果都是普通对象 console.log(person2); ``` ####

响应式数据的判断

- isRef:检查一个值是否为一个 ref 对象 - isReactive:检查一个对象是否由`reactive`创建的响应式代理 - isReadonly:检查一个对象师傅由`readonly`创建的只读代理 - isProxy:检查一个对象是否由`reactive`或`readonly`方法创建的代理 ##

Vue 响应式原理

###

vue2.x 响应原理

- 实现原理: - 对象类型通过 object.defineProperty()方法堆属性进行读取修改拦截 - 数组类型:通过重写更新数组的一系列方法来实现拦截(对数组方更新法进行重新包装) ```javascript [.line-numbers] //源数据 let preson = { name: '张三', age: 18 }; let p = {}; Object.defineProperty(p, 'name', { get() { console.log('读取了p属性name'); return preson.name; }, set(value) { console.log('修改了p属性name'); preson.name = value; document.getElementById('preson').innerHTML = preson.name; } }); ``` - 存在问题: - 新增属性、删除属性,界面不会更改(可通过手动调用 vue.set()、vue.detelt()进行更新) - 直接通过下标修改数组,界面不会更新(手动 splice()也可以更新) ###

vue3.x 响应原理

- 实现原理: - 通过 Proxy 代理拦截对象中属性的操作 - 通过 Reflect 反射对代理对象的属性进行操作 ```javascript //源数据 let preson = { name: '张三', age: 18 }; const p = new Proxy(preson, { // 拦截读取属性值 get(target, prop) { return Reflect.get(target, prop); }, // 拦截设置属性值或添加新属性 set(target, prop, value) { console.log(target, prop, value); return Reflect.set(target, prop, value); }, // 拦截删除属性 deleteProperty(target, prop) { return Reflect.deleteProperty(target, prop); } }); ``` ##

computed 与 watch

###

computed 函数

```javascript import { reactive, computed } from 'vue'; const person = reactive({ firstName: '', lastName: '' }); // 计算属性简写、传入函数返回计算后的值(只能读取不能修改) person.fullName = computed(() => person.firstName + '-' + person.lastName); // 计算属性完整写法、传入对象修改get set方法(可读可写) person.fullName = computed({ get() { return person.firstName + '-' + person.lastName; }, set(value) { const nameArr = value.split('-'); person.firstName = nameArr[0]; person.lastName = nameArr[1]; } }); ``` ###

watch 函数

- 与 Vue2 中的 watch 功能一致 - 两个小坑: - 监视 `reactive` 定义的响应式数据时 `oldValue` 无法获取,强制开启 `deep` 深度监视 - 监视 `reactive` 定义的响应式数据中某个对象属性时,`deep` 有效 ```javascript // 1、监听ref定义的多个响应式数据,immediate属性代表初始化就执行一次 watch([age, name],(newValue, oldValue) => console.log(newValue, oldValue); { immediate: true } ); // 2、监听 reactive 定义的响应式数据,oldValue 无法获取(deep 深度监视失败) watch(person,(newValue, oldValue) => console.log(newValue,oldValue); { deep: true } ); // 3、监听 reactive 定义的响应式数据中的某个属性(使用箭头函数) watch(() => person.type,(newValue, oldValue) => console.log(newValue, oldValue) ); // 4、监听 reactive 定义的响应式数据中的某些属性(使用数组嵌套箭头函数) watch([() => person.type, () => person.salary], (newValue, oldValue) => console.log(newValue, oldValue) ); // 5、特殊情况 监听 reactive 内的对象属性要开启 deep 深度检测 watch(() => person.job,(newValue, oldValue) => console.log(newValue, oldValue), { deep: true } ); ``` ###

watchEffect 函数

- `watch` 的套路就是:既要指明监视的属性,也指明监视的回调 - `watchEffect` 套路:不用指明监视哪属性,监视中的回调用到哪个,就监视哪个 - `watchEffect` 与 `computed` 的区别: - `computed` 计算出来的值 很注重返回值,必须要写 - 而 `watchEffect` 更注重过程(函数体),无需写返回值 ```javascript const age = ref(0); const name = ref('张三'); const person = reactive({ type: '前端开发', salary: 10, job: { salary: 20 } }); // watchEffect函数,函数内部用到哪个就监听哪个 watchEffect(() => { const x1 = age; console.log(person.job.salary); console.log('执行了' + x1.value); }); ``` ##

Vue3 生命周期

| 钩子函数 | 作用 | | --------------- | --------------------------------------------------------------------------------------------------------------------------- | | beforeCreate() | 实例在内存中被创建出来,还没有初始化好 data 和 methods 属性。 | | create() | 实例已经在内存中创建,已经初始化好 data 和 method,此时还没有开始编译模板。 | | beforeMount() | 已经完成了模板的编译,还没有挂载到页面中。 | | mounted() | 将编译好的模板挂载到页面指定的容器中显示。 | | beforeUpdate() | 状态更新之前执行函数,此时 data 中的状态值是最新的,但是界面上显示的数据还是旧的,因为还没有开始重新渲染 DOM 节点。 | | updated() | :此时 data 中的状态值和界面上显示的数据都已经完成了跟新,界面已经被重新渲染好了 | | beforeDestroy() | 实例被销毁之前。 | | destroyed() | 实例销毁后调用,Vue 实例指示的所有东西都会解绑,所有的事件监听器都会被移除,所有的子实例也都会被销毁。组件已经被完全销毁板。 | - 在实际开发项目中这些钩子函数如何使用 ```javascript beforeCreate : 可以在这函数中初始化加载动画 created :做一些数据初始化,实现函数自执行 mounted: 调用后台接口进行网络请求,拿回数据,配合路由钩子做一些事情 destoryed :当前组件已被删除,清空相关内容 mounted中做网络请求和重新赋值,在destoryed中清空页面数据。 ``` ###

vue3 与 vue2 的对比

```javascript Vue2--------------vue3 beforeCreate -> setup() created -> setup() beforeMount -> onBeforeMount mounted -> onMounted beforeUpdate -> onBeforeUpdate updated -> onUpdated beforeDestroy -> onBeforeUnmount destroyed -> onUnmounted activated -> onActivated deactivated -> onDeactivated errorCaptured -> onErrorCaptured ``` ###

Fragment

- 在 tamplate 中无需一个根组件包裹 - 实际上内部会将多个标签包含在一个 Fragment 虚拟元素中 - 好处: 减少标签层级, 减小内存占用 ```javascript ``` ###

provide/inject

- 提供和注入 主要用于跨层级组件(祖孙)间通信 - 在多层嵌套组件中使用,不需要将数据一层一层往下传递 - 可以县实现跨层级组件通信 父组件 ```javascript import { provide } from 'vue'; provide('info', helloClg); //传递的属性名,属性值 ``` 子孙组件 ```javascript import { inject } from 'vue'; const info = inject('info);//父组件传递的属性名 ``` ###

Teleport 传送组件