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

[复制链接]
发表于 2025-9-23 02:26:54 | 显示全部楼层 |阅读模式
效果图


代码
  1. <script lang="ts" setup>
  2. import { computed, ref, watch } from "vue";
  3. /**
  4. * 按钮属性接口
  5. */
  6. interface ButtonProps {
  7.   /** 按钮类型:default(默认)/dark/plain/link */
  8.   type?: "default" | "dark" | "plain" | "link";
  9.   /** 禁用状态 */
  10.   disabled?: boolean;
  11.   /** 按钮内容 */
  12.   text?: string;
  13.   /** 图标组件 */
  14.   icon?: any;
  15.   /** 图标宽度 */
  16.   iconWidth?: number | string;
  17.   /** 图标高度 */
  18.   iconHeight?: number | string;
  19.   /** 按钮宽度 */
  20.   width?: number | string;
  21.   /** 按钮高度 */
  22.   height?: number | string;
  23.   /** 宽度自适应 */
  24.   widthAuto?: boolean;
  25.   /** 高度自适应 */
  26.   heightAuto?: boolean;
  27.   /** 水平内边距 */
  28.   paddingX?: number | string;
  29.   /** 垂直内边距 */
  30.   paddingY?: number | string;
  31.   /** 自定义背景色 */
  32.   backgroundColor?: string;
  33.   /** 自定义边框 */
  34.   border?: string;
  35. }
  36. const props = withDefaults(defineProps<ButtonProps>(), {
  37.   type: "default",
  38.   disabled: false,
  39.   text: "",
  40.   icon: undefined,
  41.   iconWidth: 14,
  42.   iconHeight: 14,
  43.   width: 92,
  44.   height: 32,
  45.   widthAuto: false,
  46.   heightAuto: false,
  47.   paddingX: 0,
  48.   paddingY: 0,
  49.   backgroundColor: "",
  50.   border: ""
  51. });
  52. /**
  53. * 导入图标
  54. */
  55. const iconSrc = ref("");
  56. /**
  57. * 处理图标路径
  58. */
  59. const loadIcon = () => {
  60.   if (!props.icon) {
  61.     iconSrc.value = "";
  62.     return;
  63.   }
  64.   // 直接使用传入的图标路径或对象
  65.   iconSrc.value = props.icon;
  66. };
  67. // 初始加载图标
  68. loadIcon();
  69. // 监听图标属性变化,重新加载图标
  70. watch(
  71.   () => props.icon,
  72.   () => {
  73.     loadIcon();
  74.   }
  75. );
  76. // 计算样式
  77. const buttonClass = computed(() => {
  78.   return {
  79.     "ds-button": true,
  80.     [`ds-button--${props.type}`]: true,
  81.     "is-disabled": props.disabled,
  82.     "is-custom-style": props.backgroundColor || props.border
  83.   };
  84. });
  85. // 计算图标样式
  86. const iconStyle = computed(() => {
  87.   return {
  88.     width:
  89.       typeof props.iconWidth === "number"
  90.         ? `${props.iconWidth}px`
  91.         : props.iconWidth,
  92.     height:
  93.       typeof props.iconHeight === "number"
  94.         ? `${props.iconHeight}px`
  95.         : props.iconHeight,
  96.     marginRight: props.text ? "4px" : "0"
  97.   };
  98. });
  99. // 计算按钮样式
  100. const buttonStyle = computed(() => {
  101.   const paddingXValue = typeof props.paddingX === "number" ? `${props.paddingX}px` : props.paddingX;
  102.   const paddingYValue = typeof props.paddingY === "number" ? `${props.paddingY}px` : props.paddingY;
  103.   
  104.   const style = {
  105.     width: props.widthAuto ? "auto" : (typeof props.width === "number" ? `${props.width}px` : props.width),
  106.     height: props.heightAuto ? "auto" : (typeof props.height === "number" ? `${props.height}px` : props.height),
  107.     padding: props.paddingX || props.paddingY ? `${paddingYValue} ${paddingXValue}` : "",
  108.     boxSizing: "border-box" as const
  109.   };
  110.   
  111.   // 添加自定义背景色 - 支持所有CSS颜色值(包括rgba、hex、颜色名称、渐变等)
  112.   if (props.backgroundColor && !props.disabled) {
  113.     style["background"] = props.backgroundColor;
  114.   }
  115.   
  116.   // 添加自定义边框
  117.   if (props.border) {
  118.     style["border"] = props.border;
  119.   }
  120.   
  121.   return style;
  122. });
  123. const emit = defineEmits(["click"]);
  124. /**
  125. * 按钮点击事件处理
  126. * @param event 鼠标事件
  127. */
  128. const handleClick = (event: MouseEvent) => {
  129.   if (props.disabled) return;
  130.   emit("click", event);
  131. };
  132. </script>
  133. <template>
  134.   <button
  135.     :class="buttonClass"
  136.     :style="buttonStyle"
  137.     :disabled="disabled"
  138.     @click="handleClick"
  139.   >
  140.     <img v-if="icon" :src="iconSrc" :style="iconStyle" />
  141.     <span v-if="text">{{ text }}</span>
  142.     <slot v-else />
  143.   </button>
  144. </template>
  145. <style lang="scss" scoped>
  146. .ds-button {
  147.   display: flex;
  148.   align-items: center;
  149.   justify-content: center;
  150.   padding: 4px 16px;
  151.   font-size: 14px;
  152.   font-weight: 600;
  153.   text-align: center;
  154.   cursor: pointer;
  155.   border: none;
  156.   border-radius: 4px;
  157.   outline: none;
  158.   transition: all 0.3s;
  159.   &.is-custom-style {
  160.     &:hover:not(.is-disabled) {
  161.       opacity: 0.9;
  162.     }
  163.     &:active:not(.is-disabled) {
  164.       opacity: 0.8;
  165.     }
  166.     &.is-disabled {
  167.       opacity: 0.5;
  168.       cursor: not-allowed;
  169.     }
  170.   }
  171.   &--default {
  172.     color: #fff;
  173.     background: #06ad7e;
  174.     &:hover:not(.is-disabled) {
  175.       background: #07ca93;
  176.     }
  177.     &:active:not(.is-disabled) {
  178.       background: #008661;
  179.     }
  180.     &.is-disabled {
  181.       color: rgb(255 255 255 / 50%);
  182.       cursor: not-allowed;
  183.       background: rgb(6 173 126 / 50%);
  184.     }
  185.   }
  186.   &--dark {
  187.     color: #06ad7e;
  188.     background: rgb(240 251 248 / 10%);
  189.     &:hover:not(.is-disabled) {
  190.       background: rgb(240 251 248 / 15%);
  191.     }
  192.     &:active:not(.is-disabled) {
  193.       color: #008661;
  194.       background: rgb(255 255 255 / 2%);
  195.     }
  196.     &.is-disabled {
  197.       color: rgb(6 173 126 / 50%);
  198.       cursor: not-allowed;
  199.       background: rgb(240 251 248 / 5%);
  200.     }
  201.   }
  202.   &--plain {
  203.     color: #06ad7e;
  204.     background: transparent;
  205.     &:hover:not(.is-disabled) {
  206.       background: rgb(255 255 255 / 5%);
  207.     }
  208.     &:active:not(.is-disabled) {
  209.       color: #008661;
  210.       background: rgb(255 255 255 / 2%);
  211.     }
  212.     &.is-disabled {
  213.       color: rgb(6 173 126 / 50%);
  214.       cursor: not-allowed;
  215.     }
  216.   }
  217.   &--link {
  218.     color: #06ad7e;
  219.     background: transparent;
  220.     padding: 4px 0;
  221.     &:hover:not(.is-disabled) {
  222.       color: #07ca93;
  223.       background: transparent;
  224.     }
  225.     &:active:not(.is-disabled) {
  226.       color: #008661;
  227.       background: transparent;
  228.     }
  229.     &.is-disabled {
  230.       color: rgb(6 173 126 / 50%);
  231.       cursor: not-allowed;
  232.       background: transparent;
  233.     }
  234.   }
  235. }
  236. </style>
复制代码
文档

DsButton 按钮组件

一个自界说按钮组件,提供多种样式范例和状态,实用于体系中的各种交互场景。
功能特点


  • 支持四种样式范例:默认(default)、暗色(dark)、朴素(plain)和链接(link)
  • 可自界说按钮尺寸、内容和图标
  • 支持自界说配景色(支持rgba、渐变等全部CSS配景值)和边框样式
  • 支持禁用状态
  • 支持宽高自顺应和自界说内边距
  • 响应式筹划,顺应差别场景
组件API

属性

属性名阐明范例可选值默认值type按钮范例stringdefault / dark / plain / linkdefaultdisabled禁用状态booleantrue / falsefalsetext按钮文本内容string-‘’icon图标路径string-undefinediconWidth图标宽度number / string-14iconHeight图标高度number / string-14width按钮宽度number / string-92height按钮高度number / string-32widthAuto宽度自顺应booleantrue / falsefalseheightAuto高度自顺应booleantrue / falsefalsepaddingX水平内边距number / string-0paddingY垂直内边距number / string-0backgroundColor自界说配景色string全部CSS颜色值/渐变‘’border自界说边框stringCSS边框值‘’变乱

变乱名阐明回调参数click点击按钮时触发event: MouseEvent使用示例

底子用法
  1. <template>
  2.   <ds-button text="默认按钮" />
  3.   <ds-button type="dark" text="暗色按钮" />
  4.   <ds-button type="plain" text="朴素按钮" />
  5.   <ds-button type="link" text="链接按钮" />
  6. </template>
复制代码
禁用状态
  1. <template>
  2.   <ds-button text="默认按钮" disabled />
  3.   <ds-button type="dark" text="暗色按钮" disabled />
  4.   <ds-button type="plain" text="朴素按钮" disabled />
  5.   <ds-button type="link" text="链接按钮" disabled />
  6. </template>
复制代码
带图标的按钮
  1. <template>
  2.   <ds-button
  3.     text="添加"
  4.     icon="/src/assets/icons/add.png"
  5.   />
  6.   
  7.   <ds-button
  8.     type="plain"
  9.     text="删除"
  10.     icon="/src/assets/icons/delete.png"
  11.     icon-width="16"
  12.     icon-height="16"
  13.   />
  14.   
  15.   <ds-button
  16.     type="link"
  17.     text="链接"
  18.     icon="/src/assets/icons/link.png"
  19.   />
  20. </template>
复制代码
自界说配景色和边框
  1. <template>
  2.   <!-- 自定义背景色 - 十六进制 -->
  3.   <ds-button
  4.     text="蓝色按钮"
  5.     background-color="#3a7afe"
  6.   />
  7.   
  8.   <!-- 自定义背景色 - rgba -->
  9.   <ds-button
  10.     text="半透明按钮"
  11.     background-color="rgba(58, 122, 254, 0.7)"
  12.   />
  13.   
  14.   <!-- 自定义背景色 - 渐变 -->
  15.   <ds-button
  16.     text="渐变按钮"
  17.     background-color="linear-gradient(90deg, #3a7afe, #6c5ce7)"
  18.     width="120"
  19.   />
  20.   
  21.   <!-- 自定义边框 -->
  22.   <ds-button
  23.     text="带边框按钮"
  24.     type="plain"
  25.     border="1px solid #34564c"
  26.   />
  27.   
  28.   <!-- 背景色和边框都自定义 -->
  29.   <ds-button
  30.     text="自定义样式"
  31.     background-color="rgba(255, 103, 0, 0.8)"
  32.     border="1px solid #ff6700"
  33.   />
  34. </template>
复制代码
自界说尺寸
  1. <template>
  2.   <ds-button text="小按钮" width="80" height="28" />
  3.   <ds-button text="中等按钮" width="100" height="36" />
  4.   <ds-button text="大按钮" width="120" height="44" />
  5. </template>
复制代码
宽高自顺应
  1. <template>
  2.   <ds-button text="宽度自适应" width-auto />
  3.   <ds-button text="高度自适应" height-auto />
  4.   <ds-button text="宽高都自适应" width-auto height-auto />
  5. </template>
复制代码
自界说内边距
  1. <template>
  2.   <ds-button text="自定义内边距" padding-x="20" padding-y="10" />
  3.   <ds-button
  4.     type="dark"
  5.     text="更大的内边距"
  6.     padding-x="30"
  7.     padding-y="15"
  8.     width-auto
  9.   />
  10. </template>
复制代码
使用插槽

除了使用text属性设置按钮内容外,还可以使用默认插槽:
  1. <template>
  2.   <ds-button>
  3.     <span style="color: yellow">自定义内容</span>
  4.   </ds-button>
  5. </template>
复制代码
样式定制

按钮具有四种根本范例,每种范例有差别的样式:

  • default: 绿色配景,白色笔墨

    • 悬停时配景色变亮
    • 按下时配景色变暗
    • 禁用时透明度低沉

  • dark: 半透明配景,绿色笔墨

    • 悬停时配景色变亮
    • 按下时笔墨颜色变暗
    • 禁用时透明度低沉

  • plain: 透明配景,绿色笔墨

    • 悬停时有稍微配景色
    • 按下时笔墨颜色变暗
    • 禁用时透明度低沉

  • link: 透明配景,绿色笔墨,无边框和内边距

    • 悬停时笔墨颜色变亮,无配景色变化
    • 按下时笔墨颜色变暗,无配景色变化
    • 禁用时透明度低沉,鼠标样式为禁用状态

自界说样式

除了预设的四种范例,还可以通过以部属性自界说按钮样式:

  • backgroundColor: 设置按钮的配景,支持全部CSS配景属性值:

    • 十六进制颜色:#3a7afe
    • RGB/RGBA颜色:rgb(58, 122, 254) 或 rgba(58, 122, 254, 0.7)
    • 颜色名称:blue、red 等
    • 渐变:linear-gradient(90deg, #3a7afe, #6c5ce7)
    • 其他CSS配景值

  • border: 设置按钮的边框样式,可使用任何有效的CSS边框值
当使用自界说配景色或边框时,按钮的悬停和激活效果会变为透明度变化。
全局注册

该组件已通过index.ts设置为可全局注册:
  1. import DsButton from '@/components/DsButton';
  2. app.use(DsButton);
复制代码
注册后,可在任何组件中直接使用<ds-button>标签,无需单独导入。
注册入口
  1. import type { App } from "vue";
  2. import Button from "./index.vue";
  3. /**
  4. * 注册按钮组件
  5. */
  6. export default {
  7.   install(app: App) {
  8.     app.component("DsButton", Button);
  9.   }
  10. };
  11. export { Button as DsButton };
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
继续阅读请点击广告

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
回复

使用道具 举报

×
登录参与点评抽奖,加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表