前端组件库造轮子——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,点点小手支持一下,也欢迎各路大佬为我们的开源项目添砖加瓦。