Vue 3 组合式API
简介
组合式API
,是Vue 3
的新功能,主要是将组件的逻辑关注点,收集在一起,提高逻辑代码的复用率,方便复杂组件逻辑功能的理解与维护。
实现上,通过setup
组件选项,整合逻辑功能,并返回,在组件模板直接使用。setup
与methods
、data
、computed
等是向下兼容的。
需要注意的是: 在setup
中不能使用this
,会找不到组件的实例,因为setup
选项是在组件创建前执行的。methods
、data
、computed
定义的属性、方法均无法在setup
中被获取。
接下来我们通过一个简单的示例来了解组合式API的关注点分离、逻辑功能复用;
示例
示例: 一个计数器,每次遇到偶数的时候,加入列表进行展示;可排序翻转、可修改列表数据。
逻辑功能:
- 基于步幅的累加
- 列表数据更新(添加)
- 列表数据排序&翻转
- 列表数据的修改
实现
<script>
export default {
///定义组件属性
props: {
initialCount: {
type: Number,
required: false,
default: 0,
},
step: {
type: Number,
default: 1
}
},
data() {
return {
count: this.initialCount,//功能1
stepValue : this.step,//功能1
captureValues: [],//功能2、3、4
};
},
methods: {
increment() {//功能1
this.count += this.stepValue;
},
sortCaptureValues() {//功能2
this.captureValues.sort((a, b) => a > b).reverse();
},
updateCaptureValues() {//功能3
if (this.isEven) {
this.captureValues.push(this.count);
}
},
changeCaptureValues() {//功能4
this.captureValues = this.captureValues.map((a) => a * 10);
},
},
computed: {
isEven() {//功能3
return this.count % 2 == 0;
},
},
watch: {
count(newVal, oldVal) {
this.updateCaptureValues();//功能3
},
},
onmounted() {
console.log("🔥");
},
};
</script>
可以看到组件中功能实现是分散在不同的组件选项中,当功能很多很复杂的时候,代码的可读性也会大大降低。多个组件间,相同逻辑功能复用不易。 Vue 2
中,虽然可通过mixins
解决,但mixins
容易出现命名冲突等问题。
setup 实现
接下来,我们基于组合式API
来实现,代码如下:
<script>
import { ref, computed, watch } from "vue";
export default {
///定义组件属性
props: {
initialCount: {
type: Number,
required: false,
default: 0,
},
step: {
type: Number,
default: 1,
},
},
setup(props) {
///功能1:基于步幅的累加
const count = ref(props.initialCount);
const stepValue = ref(props.step);
const increment = () => (count.value += stepValue.value);
///功能2: 列表数据更新(添加)
const captureValues = ref([]);
const isEven = computed(() => count.value % 2 === 0);
const updateCaptureValues = () => {
console.log(isEven);
if (isEven.value === true) {
captureValues.value.push(count.value);
}
};
///功能3: 列表数据排序&翻转
const sortCaptureValues = () => {
captureValues.value.sort((a, b) => a > b).reverse();
};
///功能4:列表数据的修改
const changeCaptureValues = () => {
captureValues.value = captureValues.value.map((a) => a * 10);
};
///监听count
watch(count, updateCaptureValues);
return {
count,
stepValue,
increment,
isEven,
captureValues,
updateCaptureValues,
sortCaptureValues,
changeCaptureValues,
};
},
};
</script>
可以清楚的看到代码逻辑功能更加聚焦,可读性增强。 需要注意的是,组件中的数据需要通过ref
变为响应式的。
功能复用
基于setup
的实现方式,我们可将功能提取到独立的js
文件中,以便其他组件复用。
///文件路径: src/composables/useIncrement
import {ref,computed} from 'vue'
///功能1:基于步幅的累加
export default function useIncrement(initialCount,step) {
const count = ref(initialCount)
const stepValue = ref(step)
const increment = () => count.value += stepValue.value
return {
count,
stepValue,
increment
}
}
///功能2: 列表数据更新(添加)
export function useUpdateValues(count) {
const captureValues = ref([]);
const isEven = computed(() => count.value % 2 === 0);
const updateCaptureValues = () => {
if (isEven.value === true) {
captureValues.value.push(count.value);
}
};
return {
captureValues,
updateCaptureValues,
}
}
///功能3: 列表数据排序&翻转
export function useSortValues(values) {
const sortCaptureValues = () => {
values.value.sort((a, b) => a > b).reverse();
};
return { sortCaptureValues }
}
///功能4:列表数据的修改
export function useChangeValues(values,base) {
const changeCaptureValues = () => {
values.value = values.value.map((a) => a * base);
};
return {
changeCaptureValues
}
}
再将提取的功能函数引入到我们Counter
组件中:
<script>
import {watch,onMounted} from "vue";
import useIncrement, {useUpdateValues,useSortValues,useChangeValues} from "../composables/useIncrement";
export default {
///定义组件属性
props: /*...*/
setup(props) {
///累加
const {count, stepValue, increment} = useIncrement(props.initialCount, props.step)
///添加到列表
const {captureValues,updateCaptureValues} = useUpdateValues(count)
///排序数据
const {sortCaptureValues} = useSortValues(captureValues)
///改变数据
const { changeCaptureValues } = useChangeValues(captureValues,10)
///监听count
watch(count, updateCaptureValues);
///生命周期
onMounted(()=>console.log("已挂载组件"))
return {
count,
stepValue,
increment,
captureValues,
updateCaptureValues,
sortCaptureValues,
changeCaptureValues,
};
},
};
</script>
这样其他的组件就可以复用提取功能了,比如:SimpleCounter
组件复用基于步幅的累加功能。
<template>
<button @click="increment" > {{count}}</button>
</template>
<script>
import useIncrement from "../composables/useIncrement";
export default {
setup(props) {
return {
...useIncrement(0,2) // 增幅为2,初始值为0,的计数器
}
}
}
</script>
或者使用<script setup>
单文件组件中使用组合式API
的语法糖:
<template>
<button @click="increment" > {{count}}</button>
</template>
<script setup>
import useIncrement from "../composables/useIncrement";
const {count, increment} = useIncrement(0,2) // 增幅为2 ,初始值为0,的计数器
</script>
参考资料
本文使用 markdown.com.cn 排版
转载自:https://juejin.cn/post/7147981912215617573