当前位置: 首页 > news >正文

使用原生button封装一个通用按钮组件

效果图

在这里插入图片描述

代码

<script lang="ts" setup>
import { computed, ref, watch } from "vue";/*** 按钮属性接口*/
interface ButtonProps {/** 按钮类型:default(默认)/dark/plain/link */type?: "default" | "dark" | "plain" | "link";/** 禁用状态 */disabled?: boolean;/** 按钮内容 */text?: string;/** 图标组件 */icon?: any;/** 图标宽度 */iconWidth?: number | string;/** 图标高度 */iconHeight?: number | string;/** 按钮宽度 */width?: number | string;/** 按钮高度 */height?: number | string;/** 宽度自适应 */widthAuto?: boolean;/** 高度自适应 */heightAuto?: boolean;/** 水平内边距 */paddingX?: number | string;/** 垂直内边距 */paddingY?: number | string;/** 自定义背景色 */backgroundColor?: string;/** 自定义边框 */border?: string;
}const props = withDefaults(defineProps<ButtonProps>(), {type: "default",disabled: false,text: "",icon: undefined,iconWidth: 14,iconHeight: 14,width: 92,height: 32,widthAuto: false,heightAuto: false,paddingX: 0,paddingY: 0,backgroundColor: "",border: ""
});/*** 导入图标*/
const iconSrc = ref("");/*** 处理图标路径*/
const loadIcon = () => {if (!props.icon) {iconSrc.value = "";return;}// 直接使用传入的图标路径或对象iconSrc.value = props.icon;
};// 初始加载图标
loadIcon();// 监听图标属性变化,重新加载图标
watch(() => props.icon,() => {loadIcon();}
);// 计算样式
const buttonClass = computed(() => {return {"ds-button": true,[`ds-button--${props.type}`]: true,"is-disabled": props.disabled,"is-custom-style": props.backgroundColor || props.border};
});// 计算图标样式
const iconStyle = computed(() => {return {width:typeof props.iconWidth === "number"? `${props.iconWidth}px`: props.iconWidth,height:typeof props.iconHeight === "number"? `${props.iconHeight}px`: props.iconHeight,marginRight: props.text ? "4px" : "0"};
});// 计算按钮样式
const buttonStyle = computed(() => {const paddingXValue = typeof props.paddingX === "number" ? `${props.paddingX}px` : props.paddingX;const paddingYValue = typeof props.paddingY === "number" ? `${props.paddingY}px` : props.paddingY;const style = {width: props.widthAuto ? "auto" : (typeof props.width === "number" ? `${props.width}px` : props.width),height: props.heightAuto ? "auto" : (typeof props.height === "number" ? `${props.height}px` : props.height),padding: props.paddingX || props.paddingY ? `${paddingYValue} ${paddingXValue}` : "",boxSizing: "border-box" as const};// 添加自定义背景色 - 支持所有CSS颜色值(包括rgba、hex、颜色名称、渐变等)if (props.backgroundColor && !props.disabled) {style["background"] = props.backgroundColor;}// 添加自定义边框if (props.border) {style["border"] = props.border;}return style;
});const emit = defineEmits(["click"]);/*** 按钮点击事件处理* @param event 鼠标事件*/
const handleClick = (event: MouseEvent) => {if (props.disabled) return;emit("click", event);
};
</script><template><button:class="buttonClass":style="buttonStyle":disabled="disabled"@click="handleClick"><img v-if="icon" :src="iconSrc" :style="iconStyle" /><span v-if="text">{{ text }}</span><slot v-else /></button>
</template><style lang="scss" scoped>
.ds-button {display: flex;align-items: center;justify-content: center;padding: 4px 16px;font-size: 14px;font-weight: 600;text-align: center;cursor: pointer;border: none;border-radius: 4px;outline: none;transition: all 0.3s;&.is-custom-style {&:hover:not(.is-disabled) {opacity: 0.9;}&:active:not(.is-disabled) {opacity: 0.8;}&.is-disabled {opacity: 0.5;cursor: not-allowed;}}&--default {color: #fff;background: #06ad7e;&:hover:not(.is-disabled) {background: #07ca93;}&:active:not(.is-disabled) {background: #008661;}&.is-disabled {color: rgb(255 255 255 / 50%);cursor: not-allowed;background: rgb(6 173 126 / 50%);}}&--dark {color: #06ad7e;background: rgb(240 251 248 / 10%);&:hover:not(.is-disabled) {background: rgb(240 251 248 / 15%);}&:active:not(.is-disabled) {color: #008661;background: rgb(255 255 255 / 2%);}&.is-disabled {color: rgb(6 173 126 / 50%);cursor: not-allowed;background: rgb(240 251 248 / 5%);}}&--plain {color: #06ad7e;background: transparent;&:hover:not(.is-disabled) {background: rgb(255 255 255 / 5%);}&:active:not(.is-disabled) {color: #008661;background: rgb(255 255 255 / 2%);}&.is-disabled {color: rgb(6 173 126 / 50%);cursor: not-allowed;}}&--link {color: #06ad7e;background: transparent;padding: 4px 0;&:hover:not(.is-disabled) {color: #07ca93;background: transparent;}&:active:not(.is-disabled) {color: #008661;background: transparent;}&.is-disabled {color: rgb(6 173 126 / 50%);cursor: not-allowed;background: transparent;}}
}
</style>

文档

DsButton 按钮组件

一个自定义按钮组件,提供多种样式类型和状态,适用于系统中的各种交互场景。

功能特点

  • 支持四种样式类型:默认(default)、暗色(dark)、朴素(plain)和链接(link)
  • 可自定义按钮尺寸、内容和图标
  • 支持自定义背景色(支持rgba、渐变等所有CSS背景值)和边框样式
  • 支持禁用状态
  • 支持宽高自适应和自定义内边距
  • 响应式设计,适应不同场景

组件API

属性

属性名说明类型可选值默认值
type按钮类型stringdefault / dark / plain / linkdefault
disabled禁用状态booleantrue / falsefalse
text按钮文本内容string-‘’
icon图标路径string-undefined
iconWidth图标宽度number / string-14
iconHeight图标高度number / string-14
width按钮宽度number / string-92
height按钮高度number / string-32
widthAuto宽度自适应booleantrue / falsefalse
heightAuto高度自适应booleantrue / falsefalse
paddingX水平内边距number / string-0
paddingY垂直内边距number / string-0
backgroundColor自定义背景色string所有CSS颜色值/渐变‘’
border自定义边框stringCSS边框值‘’

事件

事件名说明回调参数
click点击按钮时触发event: MouseEvent

使用示例

基础用法

<template><ds-button text="默认按钮" /><ds-button type="dark" text="暗色按钮" /><ds-button type="plain" text="朴素按钮" /><ds-button type="link" text="链接按钮" />
</template>

禁用状态

<template><ds-button text="默认按钮" disabled /><ds-button type="dark" text="暗色按钮" disabled /><ds-button type="plain" text="朴素按钮" disabled /><ds-button type="link" text="链接按钮" disabled />
</template>

带图标的按钮

<template><ds-button text="添加" icon="/src/assets/icons/add.png" /><ds-button type="plain" text="删除" icon="/src/assets/icons/delete.png" icon-width="16"icon-height="16"/><ds-button type="link" text="链接" icon="/src/assets/icons/link.png" />
</template>

自定义背景色和边框

<template><!-- 自定义背景色 - 十六进制 --><ds-button text="蓝色按钮" background-color="#3a7afe"/><!-- 自定义背景色 - rgba --><ds-button text="半透明按钮" background-color="rgba(58, 122, 254, 0.7)"/><!-- 自定义背景色 - 渐变 --><ds-button text="渐变按钮" background-color="linear-gradient(90deg, #3a7afe, #6c5ce7)"width="120"/><!-- 自定义边框 --><ds-button text="带边框按钮" type="plain"border="1px solid #34564c"/><!-- 背景色和边框都自定义 --><ds-button text="自定义样式" background-color="rgba(255, 103, 0, 0.8)"border="1px solid #ff6700"/>
</template>

自定义尺寸

<template><ds-button text="小按钮" width="80" height="28" /><ds-button text="中等按钮" width="100" height="36" /><ds-button text="大按钮" width="120" height="44" />
</template>

宽高自适应

<template><ds-button text="宽度自适应" width-auto /><ds-button text="高度自适应" height-auto /><ds-button text="宽高都自适应" width-auto height-auto />
</template>

自定义内边距

<template><ds-button text="自定义内边距" padding-x="20" padding-y="10" /><ds-button type="dark" text="更大的内边距" padding-x="30" padding-y="15"width-auto/>
</template>

使用插槽

除了使用text属性设置按钮内容外,还可以使用默认插槽:

<template><ds-button><span style="color: yellow">自定义内容</span></ds-button>
</template>

样式定制

按钮具有四种基本类型,每种类型有不同的样式:

  1. default: 绿色背景,白色文字

    • 悬停时背景色变亮
    • 按下时背景色变暗
    • 禁用时透明度降低
  2. dark: 半透明背景,绿色文字

    • 悬停时背景色变亮
    • 按下时文字颜色变暗
    • 禁用时透明度降低
  3. plain: 透明背景,绿色文字

    • 悬停时有轻微背景色
    • 按下时文字颜色变暗
    • 禁用时透明度降低
  4. link: 透明背景,绿色文字,无边框和内边距

    • 悬停时文字颜色变亮,无背景色变化
    • 按下时文字颜色变暗,无背景色变化
    • 禁用时透明度降低,鼠标样式为禁用状态

自定义样式

除了预设的四种类型,还可以通过以下属性自定义按钮样式:

  • backgroundColor: 设置按钮的背景,支持所有CSS背景属性值:

    • 十六进制颜色:#3a7afe
    • RGB/RGBA颜色:rgb(58, 122, 254)rgba(58, 122, 254, 0.7)
    • 颜色名称:bluered
    • 渐变:linear-gradient(90deg, #3a7afe, #6c5ce7)
    • 其他CSS背景值
  • border: 设置按钮的边框样式,可使用任何有效的CSS边框值

当使用自定义背景色或边框时,按钮的悬停和激活效果会变为透明度变化。

全局注册

该组件已通过index.ts配置为可全局注册:

import DsButton from '@/components/DsButton';app.use(DsButton);

注册后,可在任何组件中直接使用<ds-button>标签,无需单独导入。

注册入口

import type { App } from "vue";
import Button from "./index.vue";/*** 注册按钮组件*/
export default {install(app: App) {app.component("DsButton", Button);}
};export { Button as DsButton };

相关文章:

  • 2021-11-09 C++三位数平方含有该数
  • 【数据分析实战】使用 Matplotlib 绘制直方图
  • 面向对象—有理数类的设计
  • 【软考-系统架构设计师】设计模式三大类型解析
  • Linux :进程替换
  • 模型加载常见问题
  • vue3 element-plus中的国际化在onMounted中的写法
  • 【Java学习笔记】位运算
  • vos3000外呼系统怎么给普通用户开通播放下载录音权限?
  • CSS 字体背景波浪
  • Linux操作系统--静态库和动态库的生成and四种解决加载找不到动态库的四种方法
  • 【2025最新版】火鸟门户v8.5系统源码+PC、H5、小程序 +数据化大屏插件
  • 健康养生指南
  • CMake Error at build/_deps/glog-src/CMakeLists.txt:1 (cmake_minimum_required):
  • MCP和A2A是什么?
  • Android利用MediaCodec和GLSurfaceView录制视频
  • HttpSessionAttributeListener 的用法笔记250417
  • Spring Boot 动态热更新 HTTPS 证书的实现与原理
  • 对夹式V型球阀:原理、优势与工业应用全解析
  • 【nginx】nginx的目录结构分析
  • 苏轼“胡为适南海”?
  • 占地57亩的“潮汕豪宅”面临强制拆除:曾被实施没收,8年间举行5次听证会
  • 普京批准俄方与乌克兰谈判代表团人员名单
  • 被前男友泼汽油致残后,一个女孩经历的双重灼烧
  • 财政部党组召开2025年巡视工作会议暨第一轮巡视动员部署会
  • 通辽警方侦破一起积压21年的命案:嫌疑人企图强奸遭反抗后杀人