如何封装一个灵活且美观的确认按钮组件

引言:

在前端开发中,按钮和弹窗是用户交互的重要组成部分。一个设计良好的按钮组件不仅能提升用户体验,还能减少重复代码,提高开发效率。今天,我将分享如何封装一个灵活且美观的确认按钮组件,支持多种颜色和自定义弹窗提示。

当然,作为一个程序员,我也深知写代码时的痛苦------比如当你写了一个完美的组件,结果测试告诉你:"这个按钮颜色太丑了,能不能换个粉色?"(内心 OS:粉色?你是认真的吗?)于是,我决定把这个组件设计得足够灵活,满足各种"奇怪"的需求。


1. 需求分析

在实际项目中,我们经常需要实现以下功能:

  • 按钮样式多样化:支持不同颜色和尺寸。
  • 弹窗提示:点击按钮后弹出确认弹窗,防止用户误操作。
  • 事件处理:用户确认或取消后触发相应事件。

为了满足这些需求,我决定封装一个通用的 BtnConfirm 组件。毕竟,谁也不想每次写弹窗逻辑时都重复造轮子,对吧?(除非你真的喜欢加班。)


2. 组件设计

2.1 支持属性
  • size :按钮尺寸,支持 sm(小)、md(中)、lg(大)。
  • color :按钮颜色,支持 bluegreenredpurpleorangetealpinkgrayyellow
    • (温馨提示:如果你选了 pink,请确保你的用户不会觉得你在开玩笑。)
  • confirmTitle:弹窗标题。
  • confirmMessage:弹窗内容。
  • confirmButtonText:确认按钮文本。
  • cancelButtonText:取消按钮文本。
2.2 事件
  • confirm:用户点击确认时触发。
  • cancel:用户点击取消时触发。

3. 代码实现

以下是 BtnConfirm.vue 组件的完整代码:

html 复制代码
<script setup>
import { ref } from 'vue';

const props = defineProps({
  size: {
    type: String,
    default: 'md',
    validator: (value) => ['sm', 'md', 'lg'].includes(value),
  },
  color: {
    type: String,
    default: 'blue',
    validator: (value) =>
      ['blue', 'green', 'red', 'purple', 'orange', 'teal', 'pink', 'gray', 'yellow'].includes(value),
  },
  confirmTitle: {
    type: String,
    default: '确认操作',
  },
  confirmMessage: {
    type: String,
    default: '您确定要执行此操作吗?',
  },
  confirmButtonText: {
    type: String,
    default: '确定',
  },
  cancelButtonText: {
    type: String,
    default: '取消',
  },
});

const showModal = ref(false);
const emit = defineEmits(['confirm', 'cancel']);

const getButtonStyle = () => ({
  padding: props.size === 'sm' ? '5px 10px' : props.size === 'lg' ? '15px 30px' : '10px 20px',
  fontSize: props.size === 'sm' ? '14px' : props.size === 'lg' ? '18px' : '16px',
});

const getColorStyle = () => {
  const colors = {
    blue: { button: 'linear-gradient(135deg, #409eff, #337ecc)' },
    green: { button: 'linear-gradient(135deg, #67c23a, #4e9a2f)' },
    red: { button: 'linear-gradient(135deg, #f56c6c, #c45656)' },
    purple: { button: 'linear-gradient(135deg, #9c27b0, #7b1fa2)' },
    orange: { button: 'linear-gradient(135deg, #e6a23c, #d48207)' },
    teal: { button: 'linear-gradient(135deg, #20c997, #1aa179)' },
    pink: { button: 'linear-gradient(135deg, #ff7eb9, #ff5c8d)' },
    gray: { button: 'linear-gradient(135deg, #a0a0a0, #808080)' },
    yellow: { button: 'linear-gradient(135deg, #ffc107, #e0a800)' },
  };
  return colors[props.color] || colors.blue;
};

const handleConfirm = () => {
  emit('confirm');
  showModal.value = false;
};

const handleCancel = () => {
  emit('cancel');
  showModal.value = false;
};
</script>

<template>
  <div>
    <button
      class="btn-confirm"
      :style="{ ...getButtonStyle(), background: getColorStyle().button }"
      @click.stop="showModal = true"
    >
      <slot></slot>
    </button>

    <div v-if="showModal" class="modal-overlay" @click.self="handleCancel">
      <div class="modal">
        <h3>{{ confirmTitle }}</h3>
        <p>{{ confirmMessage }}</p>
        <div class="modal-actions">
          <button class="modal-button cancel" @click="handleCancel">
            {{ cancelButtonText }}
          </button>
          <button
            class="modal-button confirm"
            :style="{ background: getColorStyle().button }"
            @click="handleConfirm"
          >
            {{ confirmButtonText }}
          </button>
        </div>
      </div>
    </div>
  </div>
</template>

<style scoped>
.btn-confirm {
  color: white;
  border: none;
  border-radius: 5px;
  cursor: pointer;
  transition: background 0.3s ease;
}

.btn-confirm:hover {
  opacity: 0.9;
}

.modal-overlay {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: rgba(0, 0, 0, 0.5);
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 1000;
}

.modal {
  background: white;
  border-radius: 10px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
  width: 300px;
  padding: 20px;
  text-align: center;
  animation: fadeIn 0.3s ease;
}

.modal h3 {
  margin: 0 0 10px;
  font-size: 18px;
  color: #333;
}

.modal p {
  margin: 0 0 20px;
  color: #666;
}

.modal-actions {
  display: flex;
  justify-content: center;
  gap: 10px;
}

.modal-button {
  padding: 8px 16px;
  border: none;
  border-radius: 5px;
  cursor: pointer;
  font-size: 14px;
  transition: background 0.3s ease;
}

.modal-button.confirm {
  color: white;
}

.modal-button.confirm:hover {
  opacity: 0.9;
}

.modal-button.cancel {
  background: #f0f0f0;
  color: #333;
}

.modal-button.cancel:hover {
  background: #e0e0e0;
}

@keyframes fadeIn {
  from {
    opacity: 0;
    transform: translateY(-20px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}
</style>

4. 使用示例

html 复制代码
<template>
  <BtnConfirm @confirm="handleConfirm" @cancel="handleCancel">
    删除
  </BtnConfirm>
</template>

<script setup>
import BtnConfirm from "@/zdpui/components/button/BtnConfirm.vue";

const handleConfirm = () => {
  console.log('用户点击了确认');
};

const handleCancel = () => {
  console.log('用户点击了取消');
};
</script>

5. 总结

通过封装 BtnConfirm 组件,我们实现了以下目标:

  • 灵活性:支持多种颜色和尺寸,满足不同场景需求。
  • 可维护性:代码结构清晰,易于扩展和维护。
  • 用户体验:弹窗提示美观,交互友好。

当然,如果你觉得这个组件还不够完美,欢迎在评论区提出建议。毕竟,程序员的世界里,没有最好,只有更好!(除非你写的代码能自动修复 Bug,那请务必联系我!)


互动话题:

你在项目中是否遇到过类似的组件需求?你是如何解决的?欢迎分享你的经验!如果你喜欢这篇文章,别忘了点赞、转发、打赏!你的支持是我持续分享的动力!

求关注、求转发、求打赏!你们的支持是我最大的动力!

相关推荐
_.Switch17 分钟前
FastAPI 的依赖注入与生命周期管理深度解析
开发语言·前端·python·中间件·性能优化·fastapi
我想学LINUX19 分钟前
【2024年华为OD机试】 (A卷,100分)- 对称美学(Java & JS & Python&C/C++)
java·c语言·javascript·c++·python·华为od
七里汀1 小时前
关于husky8.0 与 4.0的配置
javascript·git
Libby博仙1 小时前
VUE3 监听器(watch)
前端·javascript·vue.js
JINGWHALE11 小时前
设计模式 行为型 访问者模式(Visitor Pattern)与 常见技术框架应用 解析
前端·人工智能·后端·设计模式·性能优化·系统架构·访问者模式
金州饿霸1 小时前
HDFS异构存储和存储策略
前端·javascript·hdfs
处女座_三月1 小时前
多并发发短信处理(头条项目-07)
java·前端·数据库·python
zhangfeng11332 小时前
Selenium 进行网页自动化操作的一个示例,绕过一些网站的自动化检测。python编程
javascript·selenium·自动化
不想熬夜不想熬夜2 小时前
安装yarn时显示npm使用淘宝镜像安装报错
前端·npm·node.js
PorkCanteen2 小时前
ECharts饼图下钻
前端·javascript·vue.js·echarts