这是我参与「第五届青训营」伴学笔记创作活动的第 15 天
input组件
input组件相对来说比较容易,虽然容易但是依然有值得记录的点。input组件是可以让我们深度了解到双向绑定的实现原理。
$attrs
在实际使用组件库开发时,肯定会接触到 $attrs 这个属性。
这个属性在平时业务应该不常用,但是当你想进行高级组件的封装时,这个属性就是一把利器。
具体使用非常简单:v-bind: $attrs,只需要一行就能实现。
但我们还是深入了解一下这个属性,这样我们才能知己知己。
什么是$attrs?
$attrs,它的作用是将父组件的所有属性绑定到当前组件上。
在 Vue 中,有时父组件会给子组件传递大量的属性,但是可能有些属性子组件并不需要。如果要手动一一绑定这些属性,非常繁琐。这时候就可以使用 v-bind="$attrs。
更详细点:
$attrs 对象包含了除组件所声明的 props 和 emits 之外的所有其他 attribute,例如 class,style,v-on 监听器等等。
$attrs 也可以被看作是一个安全网,它可以捕获任何我们没有在组件中声明的东西。我们考虑一个只有一个属性和事件处理程序的组件
例子
当我们在input组件开发时,我们在调用组件一般是这样
<h-input v-model="input" placeholder="请输入内容"></h-input>
注意哦,这个placeholder并不是我设置的props接口,但是我们又知道input标签是带有这个属性的,因此我们可以通过$attrs,获取到这个参数,并且挂载到input标签上。
<input
class="h-input"
v-bind="$attrs"
:type="type"
:value="text"
:class="size"
ref="input"
@input.stop="handerInput"
@blur.stop="handlerBlur"
@focus.stop="handlerFocus" />
这样是不是就方便了很多?
这就是attrs的妙用之处。
双向绑定
v-model是vue中常见的语法糖,一般用于在表单元素(如 input、textarea 和 select)上实现双向数据绑定。
v-model 指令的工作原理是:在表单元素上监听输入事件并更新数据,在元素上渲染数据。实际上,它仅仅是在表单元素上绑定了 v-bind 和 v-on 的简写,所以 v-model 只能在表单元素上使用。
也就是说,在这个input组件中我们需要自己实现一个双向绑定。
实现双向绑定
双向绑定说白了就是用 v-on 和 v-bind 结合起来的语法糖
在vue3中,
当在自定义组件中使用v-model时,组件接收一个属性modelValue的值,然后通过触发update:modelValue事件来更新该值:
<h-input v-model="msg"></h-input>
<!-- 等价于 -->
<h-input :model-value="msg" @update:model-value="msg = $event"></h-input>
<!-- 建议命名按照kebab-cased规范,如:model-value,而不是modelValue -->
v-model 实现
根据上面的定义规则,我们可以这样实现一个自定义 input 组件:
// 实现1:自定义input组件
<input :value="modelValue" @input="$emit('update:modelValue', $event.target.value)">
// 传入参数
props: ['modelValue'],
// 使用
<h-input v-model="msg"></h-input>;
// 实现2
<input :value="value" @input.stop="handerInput">
props: ['modelValue'],
const value = ref()
const handerInput = (e: any) => {
text.value = e ? e.target.value : "";
emit("update:modelValue", Number(text.value));
};
v-model 参数
通过上面的示例我们发现 v-model 是接收属性modelValue的值,然后触发事件update:modelValue来更新该值,那么我们可不可以修改这个属性名modelValue呢?
其实我们只需要给v-model添加参数即可,比如:v-model:mv,这样就将modelValue换成了mv。
<input :value="mv" @input="$emit('update:mv', $event.target.value)">
props: ['mv'],
// 使用:
<h-input v-model:mv="msg"></h-input>;
正是由于 vue3 中新增了 v-model 的参数传递,所以自定义组件可以同时支持多个v-model的绑定:
<input type="text" :value="firstName" @input="$emit('update:firstName', $event.target.value)">
<input type="text" :value="lastName" @input="$emit('update:lastName', $event.target.value)">
props: { firstName: String, lastName: String, },
// 使用:
<h-input v-model:first-name="firstName" v-model:last-name="lastName"></h-input>
参考资料: