vue3时代别再写mixin,快来试试hooks

一、先来了解下什么是mixin

mixin是一种思想,一种混入的思想。混入的内容就是可以在被混入的地方使用,他会自动的将混入的东西准确的分配到指定的组件中。在vue中,mixin相当于指定混入的变量&函数放入他不混入时候该放的地方。可以认为,vue中的mixin就是相当于组件中的组件。

1.1 mixin解决了什么问题?

mixin解决了两种复用:

  1. 逻辑函数的复用
  2. 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 = () => {
    
    }

猜你喜欢

转载自blog.csdn.net/xiaofiy/article/details/130966788