一、先来了解下什么是mixin
mixin是一种思想,一种混入的思想。混入的内容就是可以在被混入的地方使用,他会自动的将混入的东西准确的分配到指定的组件中。在vue中,mixin相当于指定混入的变量&函数放入他不混入时候该放的地方。可以认为,vue中的mixin就是相当于组件中的组件。
1.1 mixin解决了什么问题?
mixin解决了两种复用:
- 逻辑函数的复用
- vue 组件配置复用
1.2 使用
在vue中,mixin定义的就是一个对象,对象中放置的vue组件相应的选项式API和对应的生命周期钩子
export const mixins = {
data() {
return {
};
},
computed: {
},
created() {
},
mounted() {
},
methods: {
clickMe() {
console.log("我是mixin中的点击事件");
},
},
};
mixin中除了不能把组件中的template模版抽出来,其他任何options-API都可以抽出来放在mixin中(vue2中的所有逻辑无非就是放在data、methods、computed、watch中,这些都可以原封不动放在mixin中)
vue中使用导出的mixin
<template>
<div id="app">
<img alt="Vue logo" src="./assets/logo.png" />
<button @click="clickMe">点击我</button>
</div>
</template>
<script>
import {
mixins } from "./mixin/index";
export default {
name: "App",
mixins: [mixins], // 注册mixin,这样mixin中所有的钩子函数等同于组件中钩子
components: {
},
created(){
console.log("组件调用minxi数据",this.msg);
},
mounted(){
console.log("我是组件的mounted生命周期函数")
}
};
</script>
1.3 注意
mixin中和vue组件中相同的钩子的优先级:
mixin中的生命周期函数会和组件的生命周期函数一起合并执行。
mixin中的data数据在组件中也可以使用。
mixin中的方法在组件内部可以直接调用。
生命周期函数合并后执行顺序:先执行mixin中的,后执行组件的。
1.4 存在的优缺点
优点:
组件中钩子函数的注册复用
缺点:
相同钩子中注册的函数名相同会发生冲突(vue中冲突的解决方案是本组件中优先级高于mixin)
定位错误需要花费时间
滥用会造成维护问题
二、hooks
我们开发中会自动抽象出逻辑函数放在utils中,utils中放的纯逻辑,不存在属于组件的东西,例如methods中定义的纯函数等。而hooks就是在utils的基础上再包一层组件级别的东西(钩子函数等)。例如:我们每次点击button都会弹出一个弹窗,自动显示当前日期。但是我将函数放在util中,每次复用都需要click=handleClick 函数放入日期函数,通过handleClick函数管理utils,那么我不如直接将handleClick也封装起来,下次直接调用,复用了methods注册的环节
2.1 hooks和utils的区别:
hooks中如果涉及到ref,reactive,computed这些api的数据,那这些数据是具有响应式的,而utils只是单纯提取公共方法就不具备响应式,因此可以把hook理解为加入vue3 api的共通方法
2.2 使用例子:
使用hooks入门的例子:
hooks文件一般是都出一个函数,例如:我需要hooks导出一个公用的name变量和setName函数
import {
ref} from 'vue'
// 导出1个 name_hooks.ts文件
// hooks中不用写在setup中
export const name_hooks = function(value: string) {
const name = ref('')
const setName = (value: string) => {
name.value = value
}
return {
name, setName
}
}
vue 引入hooks文件
<template>
<div>{
{
name }}</div>
<select @change="setName"></select> // 这里select组件的change事件会自动传value值
// 然后value值作为传参传递给setName
</template>
import {
name_hooks } from './name_hooks'
export default defineComponent({
setup() {
const {
name, setName } = name_hooks() // 注意: 通常需要通过解构赋值将需要的属性方法添加进组件中
return {
name, setName
}
}
})
以上hooks使用方法,常见的操作:
1.导出的hooks是一个函数,函数中可以使用ref,reactive,这样hooks定义的变量和方法如同在组件中一样
2.hooks函数通常返回一个对象,对象中是双向绑定的变量,在vue中间引用的时候第一件事就是解构
2.3 自定义hook
举例:表单弹框业务,属于很常见的业务场景,新增打开弹框,表单校验,编辑打开弹框进行数据回显等
import {
ref, nextTick, Ref, unref } from 'vue'
import {
setFormValues } from "@/utils/setFormValue.ts";
// 补充setFormValues 代码如下
/** 表单对象的赋值操作
const setFormValues=(form:any,data:any):void=>{
Object.keys(form).forEach(key=>{
if(Reflect.has(data,key)){
form[key]=data[key];
}
})
}
export{
setFormValues
}
*/
export default function useFormModal(formData: object, formRef: Ref) {
const visible = ref(false);
const itemInfo = ref({
});
const validStatus = ref<boolean>(false);
//校验表单
const validForm = async () => {
if (!formRef) return
await unref(formRef).validate((valid => {
validStatus.value = valid;
}))
return validStatus.value;
};
// 打开弹框
const openModal = (item: object = {
}) => {
itemInfo.value = item;
// 打开弹框
visible.value = true;
nextTick(() => {
if (!formRef) return;
// 情况表单
formRef.value.resetFields();
// 表单赋值
setFormValues(formData, item);
})
};
return {
visible,
validForm,
openModal,
itemInfo
}
}
使用
子组件表单
import type {
ElForm } from "element-plus";
import useFormModal from "hooks/useFormModal";
type FormInstance = InstanceType<typeof ElForm>;
const ruleFormRef = ref<FormInstance>();
const {
visible, validForm, itemInfo, openModal } = useFormModal(
form,
ruleFormRef
);
// 提交表单
const submitHandle = async () => {
console.log("kjjnkjk", form, itemInfo.value);
const {
submitForm } = useSubmit({
...form,
});
const valid = await validForm();
if (!valid) return;
await submitForm();
visible.value = false;
emits("success");
};
defineExpose({
//向父组件暴露方法
openModal,
});
父组件触发表单
<DialogModel ref="modalDom" @success="getData" />
const modalDom = ref(null) as Ref;
// 新增可以传{}, 编辑传整个数据
const openModel = (item: object) => {
modalDom.value.openModal({
...item,
});
};
// 添加编辑成功后
const getData = () => {
}