Button------按钮组件
需求分析
Button组件是我们平时用到的比较多的一个组件,那么我们先来看一下Button是怎么实现的。由于HTML给我们提供了<button>
标签,所以本次实现Button组件也是基于原生的<button
>来实现。
Button属性
在使用Button时,我们大部分关注的是样式的选择,所以实现一个Button组件,更多关注的是怎么给组件添加相应的样式,那么这时就可以通过给组件添加不同的属性进而动态的添加class以实现不同样式的按钮:
ts
// types.ts
// 类型
export type ButtonType = "primary" | "success" | "warning" | "danger" | "info";
// 尺寸
export type ButtonSize = "large" | "small";
// 为了和Form表单结合使用
export type NativeType = "button" | "submit" | "reset";
export interface ButtonProps {
type?: ButtonType;
size?: ButtonSize;
// 朴素类型
plain?: boolean;
// 圆角型
round?: boolean;
// 圆形
circle?: boolean;
// 禁用状态
disabled?: boolean;
nativeType?: NativeType;
// 原生 `autofocus` 属性
autofocus?: boolean;
// 加载中
loading?: boolean;
// 带icon的Button
icon?: string;
}
// 组件实例
export interface ButtonInstance {
ref: HTMLButtonElement;
}
组件实现
html
// Button.vue
<script setup lang="ts">
import { ref } from 'vue';
import type { ButtonProps } from './types';
import Icon from '../Icon/Icon.vue'
defineOptions({
name: 'YvButton'
})
withDefaults(defineProps<ButtonProps>(), {
nativeType: 'button'
})
const _ref = ref<HTMLButtonElement>()
// 暴露组件属性以及方法,以便外部使用
defineExpose({
ref: _ref
})
</script>
<template>
<button ref="_ref" class="yv-button" :class="{
[`yv-button--${type}`]: type,
[`yv-button--${size}`]: size,
'is-plain': plain,
'is-round': round,
'is-circle': circle,
'is-disabled': disabled
}" :disabled="disabled || loading" :autofocus="autofocus" :type="nativeType">
<Icon :icon="icon" v-if="icon"></Icon>
<Icon icon="spinner" spin v-if="loading"></Icon>
<span>
<slot></slot>
</span>
</button>
</template>
可以通过 defineExpose
编译器宏来显式指定在 <script setup>
组件中要暴露出去的属性:详情见Vue3官方文档 defineExpose,我们可以使用组件暴露的属性,当你需要的时候:
js
<script>
import type { ButtonInstance } from './components/Button/types'
const buttonRef = ref<ButtonInstance | null>(null)
const testRef = () => {
if (buttonRef.value) {
console.log('buttonRef', buttonRef.value.ref)
}
}
</script>
<template>
<Button ref="buttonRef" @click="testRef">Test Button</Button>
</template>
如图:
关于组件样式
组件样式比较多,本组件库大部分样式借鉴于Element Plus,这里不再一一赘述,详见 Element Plus官方
关于其他属性
Button还有更多的属性,这里只是实现一个简易版的组件,只实现常用的样式和属性,本组件库的目的也是实现常用组件的常用属性
总结
通过上述文章,实现了Button组件的基本样式和常用属性。
我们不难发现,传递属性通过Vue3父子组件之间常用的通信方式------props
,之后的组件还将用到子传父emits
,以及隔代组件通信provide
和inject
。
还有Vue3编译宏相关的APIdefineExpose
,它允许我们显式地指定哪些变量或函数应该被暴露给组件外部。这在当我们希望父组件能够访问子组件内部的某些状态或方法时非常有用。