Vue3 Hooks 对比 Vue2 Mixins 两者之间的区别?
在Vue生态中,"Hooks"这个概念随着Vue3的发布而变得火热。但很多开发者可能会有疑问:Vue2中不是也有"混入"(mixins)吗?它们有什么区别?为什么Vue3要引入Hooks?
本文将深入探讨Vue3中Hooks的实现方式,并与Vue2的Mixins进行对比,通过一个实际的例子,比较出两者使用上的区别。
一、 什么是Hooks?
Hooks 直白点说就是一个带状态的函数。其自身内部存在一套完整的响应式数据
打个比方:
-
普通函数就像一次性筷子,用完就扔
-
Hooks 就像能反复使用的餐具,每次用都能记住上次的状态
假设我们要做个登录页面,有个"发送验证码"的按钮,点完之后要倒计时60秒,这60秒内按钮是灰色的点不了,倒计时结束按钮才能再点。
这个功能在很多地方都会用到,比如注册、找回密码等等,所以我们肯定想把它抽出来复用。
三、Vue2的实现方式(Mixins)
在组件里用这个 Mixin
<template>
<div>
<input type="text" v-model="phone" placeholder="手机号" />
<button
@click="sendCode"
:disabled="isCounting"
>
{{ buttonText }}
</button>
</div>
</template>
<script>
import countdownMixin from './countdownMixin'
export default {
mixins: [countdownMixin], // 引入mixin
data() {
return {
phone: '',
}
},
methods: {
sendCode() {
console.log('发送验证码到', this.phone)
this.startCountdown()
}
}
}
</script>
可能存在的问题?
问题1:不太清除数据从哪来的?
新来的同事看到代码里的 isCounting、buttonText,不太理解变量定义在哪里?得去翻 mixin 文件才能知道。
问题2:命名冲突
假如我组件里本来就有个 isCounting 变量,想记录别的状态,但是这样会跟 mixin 里定义的冲突。谁后加载谁覆盖。
问题3:方法函数覆盖
假如在组件里也写了个重名的 startCountdown 方法,mixin 里的就被覆盖了,倒计时功能就失效了。
问题4:难定位问题
倒计时出问题了,你得去 mixin 文件里找原因,但 mixin 可能被其它地方引入。改了问题之后,不太清楚其它引用地方会不会存在问题
四、Vue2的实现方式(Hooks)
// useCountdown.js
import { ref, computed, onUnmounted } from 'vue'
export function useCountdown(initialSeconds = 60) {
// 所有的状态都写在里面
const seconds = ref(initialSeconds) // 当前剩余秒数
const isActive = ref(false) // 是否正在倒计时
let timer = null // 定时器
// 按钮上显示的文字(计算属性)
const buttonText = computed(() => {
if (isActive.value) {
return `${seconds.value}秒后重发`
}
return '发送验证码'
})
// 开始倒计时
const start = () => {
if (isActive.value) return
isActive.value = true
timer = setInterval(() => {
if (seconds.value > 0) {
seconds.value--
} else {
// 倒计时结束
clearInterval(timer)
isActive.value = false
seconds.value = initialSeconds
}
}, 1000)
}
onUnmounted(() => {
if (timer) {
clearInterval(timer)
}
})
return {
seconds,
isActive,
buttonText,
start
}
}
在组件里用Hook
<template>
<div>
<input type="text" v-model="phone" placeholder="手机号" />
<button
@click="sendCode"
:disabled="isActive"
>
{{ buttonText }}
</button>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { useCountdown } from './useCountdown'
// 组件自己的数据
const phone = ref('')
// 使用倒计时功能
const { isActive, buttonText, start } = useCountdown(60)
// 可以自己定义一个新的isCounting
const isCounting = ref(false)
const sendCode = () => {
console.log('发送验证码到', phone.value)
start() // 开始倒计时
}
const code1 = useCountdown(60) // 手机验证码倒计时
const code2 = useCountdown(120) // 邮箱验证码倒计时
</script>
这样写有啥好处?
1:代码出处一目了然
看到 isActive 就知道是从 useCountdown 来的。
好处2:命名不怕冲突覆盖,还可以对引入的变量重命名
const { isActive: codeActive, buttonText: codeBtnText } = useCountdown()
好处3:按需取用
只解构需要使用的东西。
好处4:多实例独立

浙公网安备 33010602011771号