大家好,我是 前端架构师 - 大卫。
更多优质内容请关注微信公众号 @程序员大卫。
初心为助前端人🚀,进阶路上共星辰✨,
您的点赞与关注❤️,是我笔耕不辍的灯💡。
背景
有时候我们希望一个复选框 (checkbox
) 始终保持勾选状态,即使用户点击也不会被取消。
在真实业务中,当然可以通过 :disabled
属性直接禁用实现,但这并不是本文要讨论的重点。
举个类比:假设 Vue 并没有提供 v-model.number
这样的语法糖,而我们又想实现一个只能输入数字的 input
,那实现方式就会相对繁琐。
所以本文用 checkbox
作为例子,来对比 React 和 Vue 在受控组件实现上的不同思路。
React 的实现
在 React 中,受控组件的思路非常直接:通过 state
控制值,任何用户交互最终都会回到 state
来决定组件显示。
js
import { useState } from "react";
function App() {
const [checked, setChecked] = useState(true);
const onChange = () => {
setChecked(true);
};
return <input checked={checked} type="checkbox" onChange={onChange} />;
}
export default App;
这里的核心逻辑是:
checked
始终受state
管理;- 无论用户如何点击,
onChange
都会把checked
重置为true
。
Vue3 的实现
在 Vue3 中,要让组件保持"受控",可以通过 v-model
配合事件回调来实现。 下面展示两种不同写法。
写法一:直接修改事件参数
html
<script lang="ts" setup>
import { useTemplateRef } from "vue";
const checked = defineModel({
default: true,
});
const onChange = (e: Event) => {
(e.target as HTMLInputElement).checked = true;
checked.value = true;
};
</script>
<template>
<input type="checkbox" v-model="checked" @change="onChange" />
</template>
写法二:通过 ref
引用 DOM
html
<script lang="ts" setup>
import { useTemplateRef } from "vue";
const checked = defineModel({
default: true,
});
const inputRef = useTemplateRef("input");
const onChange = () => {
if (inputRef.value) {
inputRef.value.checked = true;
}
checked.value = true;
};
</script>
<template>
<input type="checkbox" ref="input" v-model="checked" @change="onChange" />
</template>
这一写法借助 ref
,直接操作 DOM 元素来重置勾选状态。
Vue2 的实现
在 Vue2 中,由于没有 defineModel
这样的语法糖,我们通常通过 data
和 methods
来控制。
写法一:事件里修改 event.target
html
<script>
export default {
data() {
return {
checked: true,
};
},
methods: {
onChange(e) {
e.target.checked = true;
this.checked = true;
},
},
};
</script>
<template>
<input type="checkbox" v-model="checked" @change="onChange" />
</template>
写法二:使用 ref
引用
html
<script>
export default {
data() {
return {
checked: true,
};
},
methods: {
onChange(e) {
this.$refs.input.checked = true;
this.checked = true;
},
},
};
</script>
<template>
<input type="checkbox" ref="input" v-model="checked" @change="onChange" />
</template>
这一写法与 Vue3 的"写法二"类似,也是通过 ref
强行把 DOM 状态改回去。
总结
- React :天然是受控模式,所有输入值都由
state
控制,逻辑简单直接。 - Vue3 :可以通过
v-model
配合事件控制,既能改event.target
,也能通过ref
操作 DOM。 - Vue2 :思路与 Vue3 类似,只是语法更原始,需要手动处理
data
和ref
。
通过这个例子可以看到,React 在受控组件实现上更自然,而 Vue 则需要多写几行代码,但也能实现同样的效果。