前端组件库造轮子——Input组件开发教程
前言
本系列旨在记录前端组件库开发经验,我们的组件库项目目前已在Github开源,下面是项目的部分组件。文章会详细介绍一些造组件库轮子的技巧并且最后会给出完整的演示demo。

文章旨在总结经验,开源分享,有问题的话也希望路过的大佬指正。
组件开发流程
核心功能
Input组件的核心功能其实就是实现v-model,我们需要对封装出来的组件让他也拥有v-model的功能。
比如举个例子:
在vue中,我们可以直接对input标签使用v-model,但是我们没办法对封装的组件直接来使用v-model
// input 标签可以使用
<input type="text" v-model="input" />
// 自定义封装的 Input 组件 不可以使用v-model
<Input v-model="input" placeholder="请输入内容"></Input>
实现v-model
实现v-model其实就是双向绑定,比如我们可以利用vue提供的语法糖v-bind和事件调用来实现
<input v-bind:value="value" v-on:input="value= $event.target.value" />
所以,原理其实是一样的,在vue中,暴露给我们一组交互的数据
props: modelValue
emit: update:modelValue
其实就是在使用v-model时,在子组件中会用props: modelValue来接受传进来的数据,同时利用事件emit: update:modelValue 官方资料
具体实现代码就是
<template>
<input
class="input"
type="text"
:value="text"
@input.stop="handerInput" />
</template>
<script setup lang="ts">
import { ref, watch } from "vue";
const props = defineProps({
modelValue: {
type: String,
default: "",
},
});
const emit = defineEmits(["update:modelValue"]);
const handerInput = (e: Event) => {
const target = e.target as HTMLInputElement;
emit("update:modelValue", target.value);
text.value = target.value;
};
</script>
这样我们就实现完成input组件的双向绑定功能。
但是还没完,我们还需要来监听数据的修改,来更新:value:text绑定的值。
为什么要做这一步呢?
我们在刚刚其实只是实现了改变input中的值,会修改我们v-model绑定的值,但是并没有实现了v-model修改,来改变input的值。
看下面这个例子
比如,我们用两个input同时绑定上同一个value值,当我修改了一个input的值同时,另一个input的值一个也同步修改才对。
jcode
因此,我们还需要监听modelValue的值,同步修改text.value
watch(
() => props.modelValue,
(newVal) => {
if (newVal == "") return (text.value = "");
text.value = props.modelValue ? props.modelValue : "";
},
);
这样我们才算完成了这个核心功能
样式更替
在组件库开发中,我们会发现一个组件他是有多种样式可以选择的

例如在Hview-ui中,input组件就存在可以用size更换大小的样式,像这种样式开发在组件库开发中也是非常常见。
具体实现也是非常容易,我们需要在props预留出我们想要的属性,比如size,当然样式也得预先设置好,这里就不多赘述了,想比对大家来说都不是问题。
size: {
type: String,
default: "medium",
},
接下来样式更替在组件中的常用写法,这个写法就会把当前props.size的值渲染出来,放回成一个class类,接下来我们直接在template加上这个类即可。
// template
<template>
<input
class="input"
type="text"
:value="text"
:class="size" // 在这里加上size类
@input.stop="handerInput" />
</template>
// script
const size = computed(() => {
return {
[`h-input-${props.size}`]: props.size,
};
});
这样当 props.size 的值为 small 时,对象会被渲染成这样,在:class中,如果:后面为true那么就是加上h-input-small这个类了。
{
'h-input-small': 'small'
}
attrs
最后介绍一下attrs属性,想必大家平时应该不怎么会用到这个属性,但是这个属性在开发组件时相当好用,这个attrs属性可以把style,props等属性拦截下来,把其它属性渗透给孩子组件。
举个例子就明白了,
在input标签中自带着placeholder,type等属性,如果我们要开发Input组件的话,总不可能把这些属性也全自己实现吧,那就太麻烦了。
在这里,我们就可以利用attrs属性,我们把自己封装的Input组件结构一下,他在Dom渲染应该是这样的
<Input v-model="input" placeholder="请输入内容">
// Input组件内部
<template>
<input
class="input"
type="text"
:value="text"
:class="size"
@input.stop="handerInput" />
</template>
</Input>
正常来说,我们对组件传入placeholder属性,如果要获取到placeholder那么就需要在props中获取到,但是如果我们用attrs,就可以把这个属性直接加到input标签上。
因此,我们就可以用一行代码,把这些属性全部实现了。
<template>
<input
class="input"
v-bind="$attrs" // +加上attrs
type="text"
:value="text"
:class="size"
@input.stop="handerInput" />
</template>
演示demo
完整项目demo
结语
Input组件的核心开发功能就是上面这些,其他更多的详细功能开发可以参考Hview-ui项目源码
如果想要了解更多的组件轮子开发,或者组件库开发流程,更多详细的组件开发过程更新在GitHub项目源码,最后觉得我们项目or文章不错可以点个star,点点小手支持一下,也欢迎各路大佬为我们的开源项目添砖加瓦。



















