Vue3.0 中Composition API的使用
一. Composition API 和 Options API
- Options API选项api
(1)Options API 的优点是容易学习和使用,代码有明确的书写位置。
(2)Options API 的缺点是相似逻辑不容易复用,在大项目中尤为明显。
(3)Options API 可以通过mixins提取相同的逻辑,但是容易发生命名冲突且来源不清晰。 - Composition API 组合API
(1)Composition API 是根据逻辑功能来组织代码的,一个功能所有的api放到一期。
(2)即便项目很大,功能很多,都能够快速的定位到该功能的所有API。
(3)Composition API 提供了代码可读性和可维护性。 - Vue3.0 中推荐使用 Composition API,也保留了 Options API。
二. setup()
setup()
函数是一个新的组件选项,作为组件中 Composition API 的起点。- 从生命周期钩子的角度来看,
setup()
会在beforeCreate
钩子函数之前执行。 setup()
中不能执行this
,this
指向 undefined。
<template>
<div>app</div>
</template>
<script>
export default {
setup() {
console.log("setup执行了");
},
beforeCreate() {
console.log("beforeCreate执行了");
},
};
</script>
三. reactive
reactive
函数接受一个普通对象,返回该对象的响应式代理。
<template>
<div>{{ arr.title }}{{ arr.num }}</div>
<button @click="arr.num++">修改</button>
</template>
<script>
import { reactive } from "vue";
export default {
setup() {
let arr = reactive({
title: "名称",
num: 100,
});
return {
arr,
};
},
};
</script>
四. ref
ref
函数接受一个简单类型的值,返回一个可改变的ref
对象,返回的对象有唯一的属性value
。- 在
setup()
函数中,通过ref
对象的value
属性可以访问到值。 - 在模板中,
ref
属性会自动解套,不需要额外的.value
。 - 如果
ref
接受的是一个对象,会自动调用reactive
。
<template>
<div>{{ title }}</div>
<button @click="title = '名称2'">修改</button>
</template>
<script>
import {ref} from 'vue'
export default {
setup() {
let title = ref("名称1");
return {
title,
};
},
};
</script>
五. toRefs
- 把一个响应式对象转换成普通对象,该普通对象的每个
property
都是一个ref
。 reactive
的响应式功能都是赋予给对象的,但是如果给对象结构或者展开的时候,会让数丢失响应式的能力。- 使用
toRefs
可以保证该对象展开的每一个属性都是响应式的。
<template>
<div>{{ mame }}</div>
<div>{{ arr.title }}{{ arr.num }}</div>
<button @click="mame = 'ls'">修改</button>
<button @click="arr.num++">修改</button>
</template>
<script>
import { reactive, toRefs } from "vue";
export default {
setup() {
let state = reactive({
mame: "zs",
arr: {
title: "名称",
num: 100,
},
});
return {
...toRefs(state),
};
},
};
</script>
六. readonly
- 传入一个对象(响应式或普通)或
ref
,返回一个原始对象的只读代理。 - 一个只读的代理是“深度的”,对象内部任何嵌套的属性也都是只读的。
- 可以防止对象被修改。
<template>
<div>{{ num }}</div>
<button @click="num++">修改</button>
</template>
<script>
import { ref, readonly } from "vue";
export default {
setup() {
let num = ref(100);
return {
num: readonly(num),
};
},
};
</script>
七. computed
computed
函数用于创建一个计算属性。- 如果传入的是一个
getter
函数,会返回一个不允许修改的计算属性。 - 如果传入的是一个带有
getter
和setter
函数的对象,会返回一个允许修改的计算属性。
<template>
<div>今年年龄:<input v-model="age" /></div>
<div>明年年龄:<input v-model="nextAge" /></div>
<div>后年年龄:<input v-model="nextAge2" /></div>
</template>
<script>
import { ref, computed } from "vue";
export default {
setup() {
let age = ref(19);
// 计算属性
// 1.传入一个函数 getter ,返回一个不允许修改的计算属性
let nextAge = computed(() => {
return parseInt(age.value) + 1;
});
// 2.传入一个对象,包括get和set,可以创建一个可以被修改的计算属性
let nextAge2 = computed({
get() {
return parseInt(age.value) + 2;
},
// 接收一个参数,当前的值
set(value) {
age.value = value - 2;
},
});
return {
age,
nextAge,
nextAge2,
};
},
};
</script>
八. watch
watch
函数接收3个参数:
(1)参数1:数据源,可以是ref
或者getter
函数。
(2)参数2:回调函数。
(3)参数3:额外选项,是一个对象。immediate
和deep
。
{deep:true}
深度监听
{immediate:true}
立即监听watch
可以监听一个ref
或者一个带有返回值的getter
函数。watch
可以监听单个数据源,也可以监听多个数据源。watch
函数会有返回值,用于停止监听。
<template>
<div>数据1:{{ num1 }}</div>
<button @click="num1++">按钮1</button>
<br />
<div>数据2:{{ num2 }}</div>
<button @click="num2++">按钮2</button>
<br />
<div>数据3:{{ arr.title }}</div>
<button @click="arr.title = '奔驰'">按钮3</button>
</template>
<script>
import { reactive, ref, toRefs, watch } from "vue";
export default {
setup() {
let state = reactive({
num1: 100,
arr: {
title: "宝马",
},
});
let num2 = ref(100);
// 监听一个state中的值
watch(
() => state.num1,
(newValue, oldValue) => {
console.log("数据1发生变化", newValue, oldValue);
}
);
// 监听一个单独的数据
watch(num2, (newValue, oldValue) => {
console.log("数据2发生变化", newValue, oldValue);
});
// 监听一个state中的对象
watch(
() => state.arr,
(newValue) => {
console.log("数据3发生变化", newValue);
},
{
deep: true,
immediate: false,
}
);
// 监听多个值
watch(
[() => state.arr, num2],
([newArr, newNum]) => {
console.log("数据4发生变化", newArr, newNum);
},
{
deep: true,
}
);
// 监听整个state
watch(
state,
(newValue) => {
console.log("state变化了", newValue);
},
{ deep: true }
);
return {
...toRefs(state),
num2,
};
},
};
</script>
九. 生命周期钩子函数
- Vue3 提供的生命周期钩子注册函数只能在
setup()
期间同步使用。 - Vue3 生命周期钩子函数与 Vue2 对比:
(1)beforCreate
> 使用setup()
(2)created
> 使用setup()
(3)beforeMount
>onBeforeMount
(4)mounted
>onMounted
(5)beforeUpdate
>onBeforeUpdate
(6)update
>onUpdate
(7)beforeDestroy
>onBeforeUnmount
(8)destroyed
>onUnmounted
(9)errorCaptured
>onErrorCaptured
十. 模板refs
为了获得对模板内元素和组件实例的引用,我们可以像往常一样在 setup()
中声明一个 ref
并返回它。
<template>
<div ref="hRef">模板ref</div>
</template>
<script>
import { ref, onMounted } from "vue";
export default {
setup() {
let hRef = ref(null);
onMounted(() => {
console.log(hRef.value.innerHTML);
});
return {
hRef,
};
},
};
</script>
十一. 依赖注入(组件之间数据传递)
- Vue3中提供了
provide
和inject
提供依赖注入,用于实现组件之间的通讯。类似于Vue2中的provide
和inject
。 - Vue3提供的
provide
和inject
可以用于跨多级组件进行通讯。
祖级组件:
<template>
<div>这是祖级组件:{{ num }}</div>
<button @click="num++">修改</button>
<br /><br />
<Child></Child>
</template>
<script>
import { ref, provide } from "vue";
import Child from "./Child.vue";
export default {
components: {
Child,
},
setup() {
let num = ref(100);
// 后代组件调用的方法
let changeNum = (v) => {
// v : 后代组件传递过来的值
num.value = v;
};
// 向后代级组件提供属性
provide("num", num);
provide("changeNum", changeNum);
return {
num,
};
},
};
</script>
子组件
<template>
<div>这是子组件:{{ num }}</div>
<br /><br />
<Grand></Grand>
</template>
<script>
import { inject } from "vue";
import Grand from "./Grand.vue";
export default {
components: {
Grand,
},
setup() {
// 接受父组件传过来的值
let num = inject("num");
return {
num,
};
},
};
</script>
孙子组件:
<template>
<div>这是孙子组件:{{ num }}</div>
<button @click="fn">修改</button>
</template>
<script>
import { inject } from "vue";
export default {
setup() {
// 接受祖级组件传过来的值
let num = inject("num");
// 修改祖级组件中的数据
let changeNum = inject("changeNum");
let fn = () => {
// 传参改变祖级组件中的数据
changeNum(200);
};
return {
num,
fn,
};
},
};
</script>