vue3为什么选用composition-api?
先说一下vue2的options-api存在的一些问题:
1.随着功能的增长,复杂组件的代码变得越来越难以维护。 尤其发生你去新接手别人的代码时。 根本原因是 Vue 的现有 API 通过「选项」组织代码,但是在大部分情况下,通过逻辑考虑来组织代码更有意义。
2. 缺少一种比较「干净」的在多个组件之间提取和复用逻辑的机制。
vue2采用mixin的方式进行代码复用或抽离:
mixin如何使用?
1.用一个js文件将vue的script部分抽离出来:
data(){
return {}
},
methods:{},
computed:{},
filters:{},
created(){},
mounted(){
console.log("我是mixins");
}
}
2.在需要的组件引入:
<script>
import mixin from "./mixin";
export default {
mixins: [mixin]
}
</script>
mixins的一些特性:
1.mixins中的生命周期会与引入mixins的组件的生命周期整合在一起调用(mixin中的生命周期调用的比组件的快)
2.组件的data、methods、filters会覆盖mixins里的同名data、methods、filters。
3.不同mixin里的同名方法,按照引进的顺序,最后的覆盖前面的同名方法。
[mixin1,mixin2]
mixin2中的同名方法会覆盖mixin1中的方法
mixins的缺点:
1.变量来源不明确(隐式传入),不利于阅读,使代码变得难以维护。
组件里可以引入多个mixin,并直接隐式调用mixin里的变量/方法,
这会让我们有时候混乱 这些变量/方法 分别是哪个mixin里的?
2.多个mixins的生命周期会融合到一起运行,但是同名属性、同名方法无法融合,可能会导致冲突。
比如两个mixin被同一组件使用,两个mixin中有同名属性,就会导致冲突,虽然可以避免,但很容易犯错。
3.mixins和组件可能出现多对多的关系,复杂度较高(即一个组件可以引用多个mixins,一个mixins也可以被多个组件引用)
注:VUE3提出的Composition API旨在解决这些问题。mixins 的缺点是 Composition API 背后的主要动因之一,Composition API 受到 React Hooks 的启发。
vue3 hooks
hooks就是函数。
vue3 composition api就是来改变vue2 options api存在的弊端的。
hooks把代码用逻辑组织起来。达到代码的拆分和复用的目的。
规避了mixin的不足。
下面来看一些例子
获取鼠标位置的hooks
import { ref, onMounted, onUnmounted } from "vue";
export function useMousePosition() {
const x = ref(0);
const y = ref(0);
function update(e) {
x.value = e.pageX;
y.value = e.pageY;
}
onMounted(() => {
window.addEventListener("mousemove", update);
});
onUnmounted(() => {
window.removeEventListener("mousemove", update);
});
return { x, y };
}
页面中使用:
<template>
<div>鼠标x坐标:{{x}};鼠标y坐标:{{y}}</div>
</template>
<script>
import { defineComponent } from 'vue'
import { useMousePosition } from './useMousePosition'
export default defineComponent({
name: 'TestHooks',
setup() {
const { x, y } = useMousePosition();
return {
x,
y
}
}
});
</script>
判断是否点击指定元素外的区域 的hooks
/* 功能:传入一个DOM对象,判断是否点击除本身以外的其他dom上 */
import { ref, onMounted, onUnmounted, computed } from "vue";
const useClickOutside = DOM => {
// 是否点击到外部DOM
const isClickOutside = ref(false);
// 点击到dom元素上时背景色为蓝色,点击到外部时不设置背景色
const backgroundColor = computed(() => {
return isClickOutside.value ? 'blue' : 'none';
})
const hander = e => {
// contains判断一个标签是否包含另一个标签
if (DOM.value && DOM.value.contains(e.target)) {
isClickOutside.value = false;
} else {
isClickOutside.value = true;
}
};
onMounted(() => {
document.addEventListener("click", hander);
});
onUnmounted(() => {
document.removeEventListener("click", hander);
});
return {
isClickOutside,
backgroundColor
};
};
export default useClickOutside;
使用:
<template>
<div ref="DOM" class="dom">鼠标x坐标:{{x}};鼠标y坐标:{{y}}</div>
</template>
<script>
import { defineComponent, ref } from 'vue'
import { useMousePosition } from './useMousePosition'
import useClickOutside from './useClickOutside'
export default defineComponent({
name: 'TestHooks',
setup() {
// 获取鼠标位置
const { x, y } = useMousePosition();
// 点击dom区域外
const DOM = ref()
const { isClickOutside, backgroundColor } = useClickOutside(DOM);
return {
x,
y,
DOM,
isClickOutside,
backgroundColor
}
}
});
</script>
<style scoped lang='scss'>
.dom{
background: v-bind('backgroundColor')
}
</style>
上面的例子是以 逻辑来拆分代码的,每个功能写一个hooks,优点 比较明显;
变量来源清晰;功能划分清晰;不存在变量/方法命名冲突;复用方便;组织代码不会臃肿;
options-api和composition-api对比图
补充:
React中hooks的命名规范
在 react 官方文档里,对 hooks 的定义和使用提出了 “一个假设、两个只在” 的思想
一个假设: 假设任何以 「use」 开头并紧跟着一个大写字母的函数就是一个 Hook。
第一个只在: 只在 React 函数组件中调用 Hook,而不在普通函数中调用 Hook。
第二个只在: 只在最顶层使用 Hook,而不要在循环,条件或嵌套函数中调用 Hook。