Vue 中 mixins 的使用方法
在 Vue 開發中,當多個組件需要共享相同的邏輯(比如數據、方法、生命週期鈎子)時,重複編寫這些代碼會造成冗餘。mixins 就像一個 “邏輯共享容器”,能把這些通用邏輯提取出來,讓多個組件直接 “混入” 使用,既減少代碼重複,又方便統一維護。
最基礎的用法是創建一個通用 mixin,包含共享的數據和方法,然後在多個組件中引入。比如多個組件都需要處理倒計時邏輯,就可以把倒計時相關代碼提取到 mixin 中:
<!-- 定義mixin:countdown.mixin.js -->
export default {
data() {
return {
countdown: 60,
timer: null
}
},
methods: {
startCountdown() {
// 清除已有定時器,避免重複
if (this.timer) clearInterval(this.timer)
this.countdown = 60
this.timer = setInterval(() => {
if (this.countdown > 1) {
this.countdown--
} else {
clearInterval(this.timer)
this.timer = null
}
}, 1000)
}
},
beforeUnmount() {
// 組件卸載時清除定時器
if (this.timer) clearInterval(this.timer)
}
}
<!-- 組件A:使用倒計時mixin -->
<template>
<div class="component-a">
<h3>組件A</h3>
<button @click="startCountdown" :disabled="timer">
{{ timer ? `倒計時${countdown}秒` : '重新發送' }}
</button>
</div>
</template>
<script setup>
import { defineComponent } from 'vue'
import countdownMixin from './countdown.mixin.js'
// 引入mixin
export default defineComponent({
mixins: [countdownMixin]
})
</script>
<!-- 組件B:同樣使用倒計時mixin -->
<template>
<div class="component-b">
<h3>組件B</h3>
<button @click="startCountdown" :disabled="timer">
{{ timer ? `倒計時${countdown}秒` : '獲取驗證碼' }}
</button>
</div>
</template>
<script setup>
import { defineComponent } from 'vue'
import countdownMixin from './countdown.mixin.js'
export default defineComponent({
mixins: [countdownMixin]
})
</script>
這裏 countdown.mixin.js 包含了倒計時所需的數據(countdown、timer)、方法(startCountdown)和生命週期鈎子(beforeUnmount),組件 A 和組件 B 引入後,無需重複編寫代碼,就能直接使用這些數據和方法,實現倒計時功能。
mixins 不僅能共享方法和數據,還能共享生命週期鈎子。比如多個組件都需要在掛載時發送初始化請求,就可以把請求邏輯提取到 mixin 中:
<!-- 定義mixin:fetch.mixin.js -->
export default {
data() {
return {
loading: false,
dataList: []
}
},
mounted() {
// 組件掛載時自動發送請求
this.fetchData()
},
methods: {
async fetchData() {
this.loading = true
try {
// 實際開發中替換為真實接口
const res = await fetch(this.apiUrl)
this.dataList = await res.json()
} catch (err) {
console.error('請求失敗:', err)
} finally {
this.loading = false
}
}
}
}
<!-- 商品列表組件 -->
<template>
<div class="product-list">
<h3>商品列表</h3>
<div v-if="loading">加載中...</div>
<ul v-else>
<li v-for="item in dataList" :key="item.id">{{ item.name }}</li>
</ul>
</div>
</template>
<script setup>
import { defineComponent } from 'vue'
import fetchMixin from './fetch.mixin.js'
export default defineComponent({
mixins: [fetchMixin],
data() {
return {
// 覆蓋mixin中的apiUrl,指定當前組件的接口地址
apiUrl: '/api/products'
}
}
})
</script>
<!-- 用户列表組件 -->
<template>
<div class="user-list">
<h3>用户列表</h3>
<div v-if="loading">加載中...</div>
<ul v-else>
<li v-for="item in dataList" :key="item.id">{{ item.username }}</li>
</ul>
</div>
</template>
<script setup>
import { defineComponent } from 'vue'
import fetchMixin from './fetch.mixin.js'
export default defineComponent({
mixins: [fetchMixin],
data() {
return {
apiUrl: '/api/users' // 不同組件指定不同接口
}
}
})
</script>
這個 fetch.mixin.js 包含了加載狀態、數據列表和請求方法,組件引入後只需指定自己的 apiUrl,就能自動在掛載時發送請求並渲染數據。如果組件需要修改 mixin 中的邏輯,還可以直接覆蓋(比如重寫 fetchData 方法),靈活性很高。
在 Vue 3 的組合式 API 中,mixins 可以結合 setup 語法使用,通過導入 mixin 並執行的方式複用邏輯(更推薦用組合式函數,但 mixins 仍兼容):
<!-- 組合式API風格的mixin:theme.mixin.js -->
export default function themeMixin() {
const theme = ref('light')
const toggleTheme = () => {
theme.value = theme.value === 'light' ? 'dark' : 'light'
// 存儲主題到本地存儲
localStorage.setItem('theme', theme.value)
}
// 初始化時讀取本地存儲的主題
onMounted(() => {
const savedTheme = localStorage.getItem('theme')
if (savedTheme) theme.value = savedTheme
})
return {
theme,
toggleTheme
}
}
<!-- 組件中使用 -->
<template>
<div :class="theme">
<h3>組合式API + mixins</h3>
<button @click="toggleTheme">切換{{ theme === 'light' ? '深色' : '淺色' }}主題</button>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import themeMixin from './theme.mixin.js'
// 執行mixin,獲取共享的狀態和方法
const { theme, toggleTheme } = themeMixin()
</script>
<style>
.light {
background: white;
color: #333;
}
.dark {
background: #333;
color: white;
}
</style>
需要注意 mixins 的合併規則:
-
數據對象(data):組件的數據會覆蓋 mixin 中的數據(同名時以組件為準);
-
方法(methods)、計算屬性(computed):同名時組件的實現會覆蓋 mixin;
-
生命週期鈎子:組件和 mixin 中的同名鈎子都會執行,mixin 的鈎子先執行,組件的後執行。
比如 mixin 和組件都有 created 鈎子:
// mixin
created() {
console.log('mixin的created')
}
// 組件
created() {
console.log('組件的created')
}
// 執行順序:先打印“mixin的created”,再打印“組件的created”
mixins 的優勢在於簡單直接,適合提取通用邏輯,但也有侷限性:當多個 mixins 存在同名屬性或方法時,優先級難以管理;mixins 和組件之間的依賴關係不明確,調試時可能需要追溯多個 mixins。因此在 Vue 3 中,更推薦使用組合式函數(Composables)替代複雜場景的 mixins,但對於簡單的邏輯共享,mixins 依然是高效的選擇。
總的來説,mixins 是 Vue 中實現邏輯複用的經典方式,尤其適合多個組件共享相似數據、方法或生命週期邏輯的場景。合理使用 mixins 能大幅減少代碼冗餘,讓代碼維護更高效,但需注意避免過度使用和命名衝突,確保代碼的可讀性和可維護性。