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

引言:

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

当然,作为一个程序员,我也深知写代码时的痛苦------比如当你写了一个完美的组件,结果测试告诉你:"这个按钮颜色太丑了,能不能换个粉色?"(内心 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,那请务必联系我!)


互动话题:

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

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

相关推荐
胡斌附体8 分钟前
vue添加loading后修复页面渲染问题
前端·javascript·vue.js·渲染·v-if·异步加载
Dontla18 分钟前
Webpack DefinePlugin插件介绍(允许在编译时创建JS全局常量,常量可以在源代码中直接使用)JS环境变量
运维·javascript·webpack
酷爱码1 小时前
css中的 vertical-align与line-height作用详解
前端·css
沐土Arvin1 小时前
深入理解 requestIdleCallback:浏览器空闲时段的性能优化利器
开发语言·前端·javascript·设计模式·html
专注VB编程开发20年1 小时前
VB.NET关于接口实现与简化设计的分析,封装其他类
java·前端·数据库
小妖6661 小时前
css 中 content: “\e6d0“ 怎么变成图标的?
前端·css
L耀早睡2 小时前
mapreduce打包运行
大数据·前端·spark·mapreduce
咖啡の猫2 小时前
JavaScript基础-创建对象的三种方式
开发语言·javascript·ecmascript
MaCa .BaKa2 小时前
38-日语学习小程序
java·vue.js·spring boot·学习·mysql·小程序·maven
HouGISer2 小时前
副业小程序YUERGS,从开发到变现
前端·小程序