mixin 会带来什么问题
Vue2 中可以使用 mixin 来封装可复用的逻辑,它可以向一个对象注入另一个对象的所有属性,这让它非常灵活,但是同时也带来了一些问题:
- 来源不明:使用的 mixin 越多,越难找到某个属性或方法来自哪里。
- 无法精确引入:引入一个 mixin 时,会引入这个 mixin 的全部属性,因此可能会引入一些用不到的东西,也很难清楚知道到底引入了什么内容。
- 命名冲突:因为是将两个对象合并,所以可能会遇到命名冲突的问题。
如何解决上述的问题
可以转变 mixin 引入的方式,传统的 mixin 都是直接引入一个对象,我们可以封装一个函数来生成需要引入的 mixin 对象,通过参数来控制要引入的变量名、方法名。
示例一:鼠标跟踪器
实现一个鼠标跟踪功能,获取鼠标当前的 x、y 坐标,并将这个功能封装到 mixin 中。
先来看看期望中引入 mixin 的方式:
<template>
<div>{{ posX }}-{{ posY }}</div>
</template>
<script>
import { mousePosition } from "./mixin/mouse";
export default {
mixins: [
mousePosition({
x: "posX",
y: "posY",
}),
],
};
</script>
这里引入了一个 mousePosition 的方法,这个方法的返回值是一个 mixin 对象,通过参数告诉 mousePosition 方法用 posX
来接收 x
、用 posY
来接收 y
。
mousePosition
的实现如下:
const defaultOption = {
x: "x",
y: "y",
};
export function mousePosition(option = defaultOption) {
const xKey = option.x;
const yKey = option.y;
const data = {
[xKey]: 0,
[yKey]: 0,
};
document.addEventListener("mousemove", (event) => {
data[xKey] = event.clientX;
data[yKey] = event.clientY;
});
return {
data() {
return data;
},
};
}
示例二:公共表单逻辑
有这样一个业务场景:一个表单需要展现不同的样式,这种场景下可以将表单的逻辑部分封装到 mixin 中,只在组件中重写样式即可。
先看看引入方式:
<template>
<div>
<div>
<span>姓名:</span>
<input type="text" v-model="customerName" />
</div>
<div>
<span>电话:</span>
<input type="text" v-model="customerPhone" />
</div>
<button @click="onSubmit">提交</button>
</div>
</template>
<script>
import { formCore } from "./mixin/form";
export default {
mixins: [
formCore({
name: "customerName",
phone: "customerPhone",
onSubmit: "onSubmit",
}),
],
};
</script>
<style scoped>
@import "@/styles/components/formV1.css";
</style>
对于不同的组件,只需要重写 template 和 style 即可。
mousePosition
的实现如下:
const defaultOption = {
name: "name",
phone: "phone",
onSubmit: "onSubmit",
};
export function formCore(option = defaultOption) {
const nameKey = option.name;
const phoneKey = option.phone;
const onSubmitKey = option.onSubmit;
const data = {
[nameKey]: "",
[phoneKey]: "",
};
const methods = {};
if (onSubmitKey) {
methods[onSubmitKey] = function () {
const valid = () => {
if (!this[nameKey]) {
alert("请输入姓名");
return false;
}
if (!this[phoneKey]) {
alert("请输入电话");
return false;
}
return true;
};
const validResult = valid();
if (validResult) {
alert(`${this[nameKey]}-${this[phoneKey]}`);
}
};
}
return {
data() {
return data;
},
methods,
};
}
参考
我可能发现了 Vue Mixin 的正确用法——动态 Mixin