Element Plus 组件库实现:1. 实现Button(简易版)

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,以及隔代组件通信provideinject

还有Vue3编译宏相关的APIdefineExpose,它允许我们显式地指定哪些变量或函数应该被暴露给组件外部。这在当我们希望父组件能够访问子组件内部的某些状态或方法时非常有用。

相关推荐
拿不拿铁1919 小时前
Vite 5.x 开发模式启动流程分析
前端
fruge19 小时前
设计稿还原技巧:解决间距、阴影、字体适配的细节问题
前端·css
BBB努力学习程序设计20 小时前
了解响应式Web设计:viewport网页可视区域
前端·html
zhangyao94033020 小时前
uni-app scroll-view特定情况下运用
前端·javascript·uni-app
码农张20 小时前
从原理到实践,吃透 Lit 响应式系统的核心逻辑
前端
jump68020 小时前
object和map 和 WeakMap 的区别
前端
打小就很皮...20 小时前
基于 Dify 实现 AI 流式对话:组件设计思路(React)
前端·react.js·dify·流式对话
这个昵称也不能用吗?20 小时前
【安卓 - 小组件 - app进程与桌面进程】
前端
kuilaurence20 小时前
CSS `border-image` 给文字加可拉伸边框
前端·css
一 乐20 小时前
校园墙|校园社区|基于Java+vue的校园墙小程序系统(源码+数据库+文档)
java·前端·数据库·vue.js·spring boot·后端·小程序