vue2 mixin和vue3 hook 区别

vue2 mixin

定义

Mixin 是一种在 Vue 组件中复用代码的方式。我们可以将一个对象(即 mixin 对象)中的数据、方法和生命周期钩子等混入到 Vue 组件中。这样,多个组件就可以共享同一份逻辑代码。

首先,我们定义一个 mixin 对象,其中包含(datamethodscomputed)等。比如,我们可以创建一个 commonMixin.js 文件来定义一个 mixin:

javascript 复制代码
// commonMixin.js
export default {
  data() {
    return {
      message: 'Hello from mixin!'
    };
  },
  methods: {
    greet() {
      console.log(this.message);
    }
  },
  created() {
    console.log('Mixin created hook called.');
  }
};

组件使用mixin.js

局部使用 mixins:['xxx']

xml 复制代码
<template>
  <div>
    <p>{{ message }}</p>
    <button @click="greet">Greet</button>
  </div>
</template>

<script>
// 导入 mixin
import commonMixin from './commonMixin';

export default {
  name: 'HelloWorld',
  mixins: [commonMixin], // 使用 mixin
  mounted() {
    console.log('Component mounted hook called.');
  }
};
</script>

在上面的示例中, 组件通过 mixins 选项引入了 commonMixin。这意味着 组件将拥有 commonMixin 中定义的数据、方法和生命周期钩子。

全局使用 Vue.mixin(xxx)

javascript 复制代码
import Vue from 'vue'
import App from './App.vue'

import {commonMixin} from "./mixin/commonMixin.js"

Vue.mixin(commonMixin);

Vue.config.productionTip = false

new Vue({
  render: h => h(App),
}).$mount('#app')

Mixin 的冲突处理

如果组件和 mixin 中都定义了相同的选项,Vue 将遵循一定的优先级规则来处理这些冲突:

  • 数据 :如果组件和 mixin 中有相同的 data 字段,组件中的 data 会覆盖 mixin 中的 data

  • 方法:如果组件和 mixin 中有同名的方法,组件中的方法会覆盖 mixin 中的方法。

  • 生命周期钩子 :如果组件和 mixin 中有相同的生命周期钩子(如 created),它们都会被调用,且 mixin 中的钩子会在组件中的钩子之前调用。

javascript 复制代码
// commonMixin.js
export default {
  data() {
    return {
      message: 'Hello from mixin!'
    };
  },
  methods: {
    greet() {
      console.log('Mixin greet');
    }
  },
  created() {
    console.log('Mixin created hook called.');
  }
};

// HelloWorld.vue
<template>
  <div>
    <p>{{ message }}</p>
    <button @click="greet">Greet</button>
  </div>
</template>

<script>
import commonMixin from './commonMixin';

export default {
  name: 'HelloWorld',
  mixins: [commonMixin],
  data() {
    return {
      message: 'Hello from component!'
    };
  },
  methods: {
    greet() {
      console.log('Component greet');
    }
  },
  created() {
    console.log('Component created hook called.');
  }
};
</script>

在这个例子中,组件中 message 的值会覆盖 mixin 中的值,greet 方法中的实现会覆盖 mixin 中的方法,created 钩子的调用顺序是 mixin 先调用,然后组件中的 created 钩子调用。

使用 Mixin 的注意事项

  • 命名冲突:为了避免命名冲突,建议使用明确且独特的命名方式。
  • 复杂性:过度使用 mixin 可能会导致代码难以跟踪和调试。可以考虑使用 Vue 的组合式 API 来替代 mixin,以提高代码的可读性和可维护性。

mixin 主要用于以下场景:

1. 共享功能和逻辑

当多个组件需要使用相同的功能或逻辑时,mixin 是一个有效的解决方案。通过将共享的逻辑提取到一个 mixin 中,我们可以避免重复代码。例如,多个组件可能都需要处理表单验证或数据格式化,这时可以将这些功能封装到一个 mixin 中:

javascript 复制代码
js
 代码解读
复制代码
// validationMixin.js
export default {
  methods: {
    validateEmail(email) {
      const re = /^[^\s@]+@[^\s@]+.[^\s@]+$/;
      return re.test(email);
    }
  }
};

// UserForm.vue
<template>
  <form @submit.prevent="handleSubmit">
    <input v-model="email" placeholder="Enter your email" />
    <button type="submit">Submit</button>
  </form>
</template>

<script>
import validationMixin from './validationMixin';

export default {
  mixins: [validationMixin],
  data() {
    return {
      email: ''
    };
  },
  methods: {
    handleSubmit() {
      if (this.validateEmail(this.email)) {
        alert('Email is valid!');
      } else {
        alert('Email is invalid!');
      }
    }
  }
};
</script>

2. 封装重复的生命周期钩子

有时候,多个组件可能需要在相同的生命周期阶段执行某些操作。例如,所有组件都需要在 created 钩子中初始化数据或进行 API 请求。可以将这些操作封装到 mixin 中:

javascript 复制代码
js
 代码解读
复制代码
// dataFetchMixin.js
export default {
  created() {
    this.fetchData();
  },
  methods: {
    async fetchData() {
      // 假设有一个 API 请求
      try {
        const response = await fetch('https://api.example.com/data');
        this.data = await response.json();
      } catch (error) {
        console.error('Failed to fetch data:', error);
      }
    }
  },
  data() {
    return {
      data: null
    };
  }
};

// DataComponent.vue
<template>
  <div>
    <pre>{{ data }}</pre>
  </div>
</template>

<script>
import dataFetchMixin from './dataFetchMixin';

export default {
  mixins: [dataFetchMixin]
};
</script>

3. 跨组件通信

在 Vue 2 中,mixin 可以用来管理跨组件通信。例如,多个子组件可以通过 mixin 共享父组件传递的数据或方法:

javascript 复制代码
js
 代码解读
复制代码
// communicationMixin.js
export default {
  methods: {
    emitEvent(message) {
      this.$emit('custom-event', message);
    }
  }
};

// ParentComponent.vue
<template>
  <div>
    <ChildComponent @custom-event="handleEvent" />
  </div>
</template>

<script>
import communicationMixin from './communicationMixin';
import ChildComponent from './ChildComponent.vue';

export default {
  components: { ChildComponent },
  mixins: [communicationMixin],
  methods: {
    handleEvent(message) {
      console.log('Received message:', message);
    }
  }
};
</script>

// ChildComponent.vue
<template>
  <button @click="sendMessage">Send Message</button>
</template>

<script>
import communicationMixin from './communicationMixin';

export default {
  mixins: [communicationMixin],
  methods: {
    sendMessage() {
      this.emitEvent('Hello from ChildComponent');
    }
  }
};
</script>

4. 封装组件的默认行为

对于有相似默认行为的多个组件,可以将这些默认行为封装到 mixin 中。例如,处理表单提交、数据清理等:

javascript 复制代码
js
 代码解读
复制代码
// formMixin.js
export default {
  methods: {
    handleSubmit() {
      console.log('Form submitted');
      // 处理表单提交逻辑
    },
    clearForm() {
      this.$data = this.$options.data();
    }
  }
};

// LoginForm.vue
<template>
  <form @submit.prevent="handleSubmit">
    <!-- 表单内容 -->
    <button type="submit">Login</button>
  </form>
</template>

<script>
import formMixin from './formMixin';

export default {
  mixins: [formMixin]
};
</script>

vue 3 hook

定义

本质上它就是一个函数,有点类似于vue2的mixin技术,都是将代码混入组件中。

作用

将重复的逻辑抽离出来,提高代码复用率,在组件里使用hook时,相当于函数里的相关api方法都移入了组件里,让setup的逻辑更加简洁清晰。

使用

useSum.ts中内容如下:

csharp 复制代码
```
import {ref,onMounted} from 'vue'

export default function(){
  let sum = ref(0)

  const increment = ()=>{
    sum.value += 1
  }
  const decrement = ()=>{
    sum.value -= 1
  }
  onMounted(()=>{
    increment()
  })

  //向外部暴露数据
  return {sum,increment,decrement}
}		
```

useDog.ts中内容如下:

csharp 复制代码
```
import {reactive,onMounted} from 'vue'
import axios,{AxiosError} from 'axios'

export default function(){
  let dogList = reactive<string[]>([])

  // 方法
  async function getDog(){
    try {
      // 发请求
      let {data} = await axios.get('https://dog.ceo/api/breed/pembroke/images/random')
      // 维护数据
      dogList.push(data.message)
    } catch (error) {
      // 处理错误
      const err = <AxiosError>error
      console.log(err.message)
    }
  }

  // 挂载钩子
  onMounted(()=>{
    getDog()
  })
	
  //向外部暴露数据
  return {dogList,getDog}
}
```

组件中具体使用:

xml 复制代码
```
<template>
  <h2>当前求和为:{{sum}}</h2>
  <button @click="increment">点我+1</button>
  <button @click="decrement">点我-1</button>
  <hr>
  <img v-for="(u,index) in dogList.urlList" :key="index" :src="(u as string)"> 
  <span v-show="dogList.isLoading">加载中......</span><br>
  <button @click="getDog">再来一只狗</button>
</template>

<script lang="ts">
  import {defineComponent} from 'vue'

  export default defineComponent({
    name:'App',
  })
</script>

<script setup lang="ts">
  import useSum from './hooks/useSum'
  import useDog from './hooks/useDog'
	
  let {sum,increment,decrement} = useSum()
  let {dogList,getDog} = useDog()
</script>
```
csharp 复制代码
// 引入组合式api
import { reactive } from 'vue'

// 暴露hook函数
export default function () {
  // 数据: 存储宽高
  const point = reactive({
    width: 0,
    height: 0,
    str: ''
  })

  // 函数: 设置宽高
  function setWH (event) {
    point.width = event.width
    point.height = event.height
    point.str = event.str
  }

  // 函数: 设置宽高
  function getWH (event) {
    screen.width = document.documentElement.clientWidth
    screen.height = document.documentElement.clientHeight
    point.str = event.str || '自动获取可视化宽高'
  }

  // 返回数据
  return { point, setWH, getWH }
}

总结区别

1. 代码组织方式

特性 Vue 2 Mixin Vue 3 Composition API(Hook)
代码结构 通过混入对象的选项(datamethods 等)复用逻辑。 通过函数(setup)和自定义 Hook 组织逻辑。
逻辑聚合 逻辑分散在组件的各个选项中(如 datamethods)。 相关逻辑集中在一个函数中(如 useUser)。
复用方式 静态混入,所有属性和方法自动合并到组件中。 动态组合,按需引入功能函数。

示例对比

  • Mixin(Vue 2):

    javascript 复制代码
    // userMixin.js
    export default {
      data() {
        return { username: 'Alice' };
      },
      methods: {
        login() { /* ... */ }
      }
    };
    
    // 组件中使用
    export default {
      mixins: [userMixin],
      methods: {
        // 可能覆盖 Mixin 的同名方法!
        login() { /* ... */ }
      }
    };
  • Composition API(Vue 3):

    javascript 复制代码
    // useUser.js
    import { ref } from 'vue';
    export function useUser() {
      const username = ref('Alice');
      const login = () => { /* ... */ };
      return { username, login };
    }
    
    // 组件中使用
    import { useUser } from './useUser';
    export default {
      setup() {
        const { username, login } = useUser();
        return { username, login };
      }
    };

2. 作用域与命名冲突

特性 Vue 2 Mixin Vue 3 Composition API(Hook)
作用域 Mixin 的属性和方法与组件直接合并,共享同一作用域。 组合函数返回的属性和方法需在 setup 中显式暴露。
命名冲突 高:Mixin 和组件同名属性/方法会覆盖。 低:通过显式命名或解构赋值避免冲突。

示例

  • Mixin 的命名冲突

    javascript 复制代码
    // Mixin 定义
    const mixin = {
      data() {
        return { count: 0 };
      }
    };
    
    // 组件定义
    export default {
      mixins: [mixin],
      data() {
        return { count: 42 }; // 覆盖 Mixin 的 count!
      }
    };
  • Composition API 的显式命名

    javascript 复制代码
    // useCounter.js
    export function useCounter() {
      const count = ref(0);
      return { count };
    }
    
    // 组件中使用
    export default {
      setup() {
        const { count: counter } = useCounter();
        return { counter }; // 重命名避免冲突
      }
    };

3. 灵活性与可维护性

特性 Vue 2 Mixin Vue 3 Composition API(Hook)
逻辑组合 静态:混入的代码无法动态调整。 动态:可灵活组合多个 Hook,甚至条件复用。
依赖管理 隐式:Mixin 的依赖关系不透明。 显式:通过函数参数传递依赖,关系清晰。
调试难度 高:多个 Mixin 的代码合并后难以追踪来源。 低:每个 Hook 是独立模块,调试更直观。

示例

  • 动态组合多个 Hook

    javascript 复制代码
    // 组件中使用多个 Hook
    import { useUser, useCounter } from './hooks';
    export default {
      setup() {
        const { username } = useUser();
        const { count } = useCounter();
        return { username, count };
      }
    };

4. 类型支持(TypeScript)

特性 Vue 2 Mixin Vue 3 Composition API(Hook)
类型推断 弱:Mixin 的属性和方法类型难以推导。 强:组合函数可明确定义类型,支持完整类型推断。

示例

  • Composition API 的类型定义

    typescript 复制代码
    // useUser.ts
    import { ref } from 'vue';
    interface User {
      username: string;
      login: () => void;
    }
    
    export function useUser(): User {
      const username = ref('Alice');
      const login = () => { /* ... */ };
      return { username, login };
    }

5. 生命周期管理

特性 Vue 2 Mixin Vue 3 Composition API(Hook)
生命周期钩子 Mixin 的钩子与组件钩子合并,执行顺序不可控。 使用 onMounted 等函数显式注册,逻辑集中。

示例

  • Mixin 的钩子合并

    j

    javascript 复制代码
    // Mixin
    export default {
      created() { console.log('Mixin created'); }
    };
    
    // 组件
    export default {
      mixins: [mixin],
      created() { console.log('Component created'); }
    };
    // 输出顺序:Mixin created → Component created
  • Composition API 的钩子注册

    javascript

    复制

    javascript 复制代码
    import { onMounted } from 'vue';
    export default {
      setup() {
        onMounted(() => {
          console.log('Component mounted');
        });
      }
    };

总结

维度 Vue 2 Mixin Vue 3 Composition API(Hook)
代码组织 分散在组件选项中,逻辑碎片化。 逻辑集中,按功能组织为独立函数。
命名冲突 容易冲突,需手动管理。 通过作用域隔离和显式暴露避免冲突。
灵活性 静态混入,无法动态调整。 动态组合,按需复用逻辑。
类型支持 类型推导困难。 完整的 TypeScript 支持。
调试维护 隐式依赖,调试复杂。 显式依赖,模块化,易于调试。
生命周期 钩子自动合并,顺序不可控。 显式注册,逻辑集中管理。
选择建议
  • Vue 2 项目:可继续使用 Mixin,但需注意命名冲突和代码规范。
  • Vue 3 项目 :优先使用 Composition API,通过自定义 Hook 实现更灵活、安全的代码复用。
相关推荐
计算机学姐21 分钟前
基于Asp.net的驾校管理系统
vue.js·后端·mysql·sqlserver·c#·asp.net·.netcore
ZXT6 小时前
面试精讲 - vue3组件之间的通信
vue.js
念九_ysl7 小时前
深入解析Vue3单文件组件:原理、场景与实战
前端·javascript·vue.js
Jenna的海糖7 小时前
vue3如何配置环境和打包
前端·javascript·vue.js
灵感__idea7 小时前
Vuejs技术内幕:数据响应式之3.x版
前端·vue.js·源码阅读
鱼樱前端7 小时前
📚 Vue Router 4 核心知识点(Vue3技术栈)面试指南
前端·javascript·vue.js
计算机-秋大田8 小时前
基于Spring Boot的宠物健康顾问系统的设计与实现(LW+源码+讲解)
java·vue.js·spring boot·后端·课程设计
程序员大澈8 小时前
1个基于 Three.js 的 Vue3 组件库
javascript·vue.js
程序员大澈8 小时前
3个 Vue Scoped 的核心原理
javascript·vue.js
计算机学姐8 小时前
基于Asp.net的教学管理系统
vue.js·windows·后端·sqlserver·c#·asp.net·visual studio