Composition API
1、Mixin混入
组件与组件之间偶尔存在相同的功能模块,在开发维护过程中我们希望方便后续开发维护
基本使用
1、将重复的代码封装到了一个JS文件中
2、在需要使用到的组件内部进行引入并使用
export default{
mixin:[LoginMixin];
}
javascript
合并规则:
当Mixin对象内的设置与组件内设置出现不一致时,在这种情况下,Vue是如何处理这种情况的吗?
这里分成不同的情况来进行处理;情况一:如果是data函数的返回值对象
1、返回值对象默认情况下会进行合并;
2、如果data返回值对象的属性发生了冲突,那么会保留组件自身的数据;
情况二:如何生命周期钩子函数
生命周期的钩子函数会被合并到数组中,都会被调用;
第三种情况:其中 methods、components 和 directives 会被赋值,并整合为一个单一的对象。
1、比如都有methods选项,并且都定义了方法,那么它们都会生效;
2、但是如果对象的key相同,那么会取组件对象的键值对;
全局混入
const app = createApp(App);
app.mixin({
created() {
console.log("global mixin created");
},
});
app.mount("#app");
javascript
2、为什么要 从options API 进化到Composition API
当我们开发某个功能时, 该功能所涉及的代码逻辑将被分配到各个属性中
当一个组件规模增大或结构更为复杂时(或者:随着组件规模的增长或结构变得更加复杂),涉及的相关关注点数量会上升(或者:增加)。这样一来(或者:从而),同一个功能的逻辑会被分解成多个部分(或者:被分散地处理),这可能导致整个系统的代码变得更加冗长并难以维护。
由于该组件采用了分散式的代码架构,在理解和维护过程中显得异常复杂,并隐含了潜在的逻辑漏洞。在处理单一的具体功能模块时,则需要频繁地切换至对应的代码段落。
3、setup
setup函数的参数
第一个参数:props
props充当参数传递给setup函数中,并且我们能够通过参数进行直接使用;
第二个参数:context
attrs :所有的非prop的attribute;
slots :由父组件提供的槽位(这些在使用渲染函数返回时会有特定的应用场景,在后续内容中将详细讲解)//基本不用
当组件内部需要发送事件时,我们使用emit(由于无法访问this属性,因此不能直接通过this.$emit来发送事件)
setup函数的返回值
setup函数的返回值可以在模板template中被使用 ,这表明我们可以通过setup函数的返回值来取代data选项 ;
我们可以返回一个执行函数来代替在methods中定义的方法
setup(props) {
const changeMsg = (props) => {
props.message.value = "huajie";
};
return {
changeMsg,
};
},
javascript
setup不可以使用this
这个值并未直接关联于当前组件实例,在setup函数执行前尚未进行任何数据预处理或计算操作(即data、computed、methods等均未被预先计算或解析),因此,在setup阶段无法访问或引用this属性。
4、ReactiveAPI(响应式)
定义:为在setup中定义的数据提供响应式的特性。
const state = reactive({
name: "xueyagang",
age: 18,
});
javascript
为什么reactiveAPI是响应式的?
因为当我们调用Reactive函数处理我们的数据后,在后续的数据访问中会自动进行依赖收集;每当数据发生变化时;所有收集到的依赖都会触发相应的响应式操作(如界面更新)。实际上;我们编写的data选项也会交给Reactive函数来管理作为响应式对象运行。
5、RefAPI(响应式)
reactive API对输入的类型有约束,在这种情况下我们必须接收一种对象或数组类型的输入
如果我们传入一个基本数据类型(String、Number、Boolean)会报一个警告;
ref表示一个可变的响应式对象,在这种引用中包含了其内部的值这一特征便形成了ref这一术语
// 它内部的值实在ref的value熟悉中被维护的
const message = ref("xueyagang"
javascript
注意:
在模板中加入ref的值时,Vue会自动协助完成解包操作;因此无需在模板中采用ref.value的方式处理
在设置函数的内部过程中,在set方法调用之前,在set方法调用之后,在set方法调用的过程中,在set方法调用的时候
6、认识readonly
我们采用reactive或者ref能够获取到一个响应式的对象,在某些情况下我们将传递给其他地方(组件)的那个响应式对象希望能够在另一个地方(组件)中被使用但又不被修改这个时候如何防止这种情况的发生呢
readonly将返回原生对象的一个不可变代理(即该Proxy实例仍然)。此外,在这种情况下(即此Proxy实例),其设置属性的方法其实在其生命周期内已经被强行阻止,并无法对其实体进行修改)。
在开发中常见的readonly方法会传入三个类型的参数:
1、普通对象(既不可被修改,也没有响应式的特性)
reactive依赖数据的对象(子组件无法独立配置;但会随之响应父组件的数据变化)
3、ref作用于的对象(子组件无法单独更改配置,并且当父组件的数据发生变化时,相应的子组件也会随之更新)
7、Reactive判断的API
1、isProxy:检查对象是否是由reactive 或readonly创建的proxy。
isReactive:判断所给对象是否为由reactive生成的响应式代理;如果是readonly构建的对象,并且包裹了一个由另一个reactive生成的对象,则该函数也会返回true;
3、isReadOnly:检查对象是否是由readonly创建的只读代理。
toRaw:返回reactive或readonly代理的原始数据源(不建议长时间引用原始对象,请注意避免直接引用)
shallowReactive:生成一个响应式的代理接口或组件(这里指代的是),该代理仅追踪其自身属性的动态变化而不进行嵌套对象中的深层次动态转换(此处问题点指的是)。
shallowReadonly:通过生成一个proxy对象,在其属性上实现不可读性配置,并且避免对嵌套对象执行深度只读转换操作(具体来说是支持还是不支持深入的对象进行深度只读转换)。
8、toRefs
当我们采用ES6解构赋值语法从reactive返回的对象中拆分出所需值时
const state = reactive({
name: "xueyagang",
age: 18,
});
const { name, age } = state;
javascript
如何结构出响应式的属性
toRefs的函数,可以将reactive返回的对象中的属性都转成ref;
再次进行结构出来的name 和age 本身都是ref的;
const { name, age } = toRefs(state);
javascript
只转换一个reactive对象中的属性为ref
const name = toRef(state, 'name');
const { age } = state;
const changeName = () => state.name = "huajie"
javascript
9、computed
setup中如何使用computed
方式一、采用getter函数作为输入,并生成与该值对应的固定不变的对象;
const fillname = computed(() => {
return aa.value;
});
javascript
方式二、接收一个具有get 和set 的对象,返回一个可变的(可读写)ref 对象;
const fillname = computed({
get: () => {
return firstName.value + " " + lastName.value;
},
set: (newvalue) => {
const names = newvalue.split(" ");
firstName.value = names[0];
lastName.value = names[1];
},
});
javascript

10、watchEffect
注意:
watchEffect接受传入的函数将立刻被调用一次,并在其运行过程中会收集所需的依赖项
2、只有收集的依赖发生变化时,watchEffect传入的函数才会再次执行
const firstName = ref("hahah");
const lastName = ref("HUAJIE");
watchEffect(() => {
console.log('执行',firstName.value,lastName.value);
})
javascript
1、watchEffect的停止侦听
当遇到特定情况时,如果我们想要停止监听,则可以考虑访问watchEffect返回值的方法,并调用该方法即可完成任务。
const stop = watchEffect(() => {
console.log('执行',firstName.value,lastName.value);
})
// 再合适的时机调用这个函数
javascript
2、watchEffect清除副作用
我们给watchEffect传递的函数,在被回调时实际上捕获了一个参数onInvalidate。
当潜在的副作用将要重新执行或者侦听器被停止时,该回调函数会被调用
const stop = watchEffect((onInvalidate) => {
const timer = setTimeout(() => {
console.log("2秒后打印");
}, 2000);
onInvalidate(() => {
clearTimeout(timer);
});
});
javascript
3、watchEffect的执行时机(结合第11点看)
setup() {
const title = ref(null);
watchEffect(() => {
console.log(title.value); // null <h2></h2>
});
return {
title,
};
},
javascript
由于setup函数在运行中会立刻触发传入的副作用函数,在这种情况下DOM未完成DOM解析而导致打印结果为null。
当DOM加载DOM结构时,在title属性的ref对象上会设置新的属性值,在此过程中可能会引发副作用函数的执行;这些后续操作会输出相应的元素信息;
4、调整watchEffect的执行时机
watchEffect(() => {
console.log(title.value); // null <h2></h2>
},[
flush: "post"
]);
javascript
默认情况下,默认值为pre时,在元素挂载或更新前执行操作;选择post时,默认不会在第一次打印过程中执行操作;flush选项可配置同步参数以强制触发同步触发机制。
11、setup中使用ref
<template>
<div>
<h2 ref="title">标题</h2>
</div>
</template>
<script>
import { ref } from "vue";
export default {
setup() {
const title = ref(null);
return {
title,
};
},
};
javascript

12、Watch的使用
1、侦听单个数据源
const state = reactive({
name: "why",
age: 18,
});
watch(
() => state.name,
(newValue, oldValue) => {
console.log(newValue, oldValue);
}
);
javascript

2、侦听多个数据源
侦听器还可以使用数组同时侦听多个源:
watch(
[name,age],
(newValue, oldValue) => {
console.log(newValue, oldValue);
}
);
watch(
() => [...state],
(newValue, oldValue) => {
console.log(newValue, oldValue);
}
);
javascript

3、watch的选项
watch(
() => [...state],
(newValue, oldValue) => {
console.log(newValue, oldValue);
},{
deep: true,
immediate: true
}
);
javascript
13、生命周期钩子
beforeCreate => not needed created => not needed
beforeMount => onBeforeMount mounted => onMounted
beforeUpdate = onBeforeUpdate updated => onUpdated
beforeUnMount => onBeforeUnMount unMounted => on Unmounted
activated => onActivated deactivated => onDeactivated
因为set up是围绕beforeCreate和created生命周期钩子展开的,在这种情况下无需显式地定义它们;此外,在这些钩子内编写的任何代码都应直接包含在set up函数体内
14、Provide函数
我们可以通过provide来提供数据:
provide可以传入两个参数: name:提供的属性名称;value:提供的属性值
setup() {
const name = ref("xueyg");
provide("name", name);
},
javascript
15、Inject函数
const name = inject("name","当父组件不传时的默认值")
javascript
16、自定义指令
自定义指令分为两种:
1、自定义局部指令:组件中通过directives 选项,只能在当前组件中使用;
2、自定义全局指令:app的directive 方法,可以在任意组件中被使用;
app.directive("focus", {
mounted(el) {
el.focus();
},
});
javascript
指令的生命周期
一个指令定义的对象,Vue提供了如下的几个钩子函数:
created :在绑定元素的attribute 或事件监听器被应用之前调用;
beforeMount :当指令第一次绑定到元素并且在挂载父组件之前调用;
mounted :在绑定元素的父组件被挂载后调用;
beforeUpdate :在更新包含组件的VNode之前调用;
updated :在包含组件的VNode及其子组件的VNode更新后调用;
beforeUnmount :在卸载绑定元素的父组件之前调用;
unmounted :当指令与元素解除绑定且父组件已卸载时,只调用一次;
17、指令的参数和修饰符
1、info是参数的名称
2、aaa-bbb是修饰符的名称
3、后面是传入的具体的值
在我们的生命周期中,我们可以通过bindings 获取 到对应的内容
18、Teleport
eleport翻译过来是心灵传输、远距离运输的意思
它有两个属性: to :指定将其中的内容移动到的目标元素,可以使用选择器;
disabled :是否禁用teleport 的功能;
<div class="fater">
<teleport to="body">
<h2>xueyagang</h2>
</teleport>
</div>
javascript

