实现一个轮盘式按钮

491 阅读3分钟

这种轮盘式可收起的按钮大家应该都见过的吧,对于一些平时使用频率不高的按钮组,我们就可以用这种轮盘按钮来处理,平时收缩起来只展示一个主按钮,点击主按钮之后才会将子按钮围绕主按钮显示出来

在线体验

码上掘金

codePen

codepen.io/yongtaozhen…

代码实现

html部分

html 部分比较简单,主按钮在 html 中直接创建,子按钮根据配置信息在 js 中动态生成

<div class="wheel-btn-container">
  <button class="main-btn" id="mainBtn">
    <span>展开</span>
  </button>
  <ul class="sub-buttons" id="subButtons"></ul>
</div>

css部分

主按钮交互

  • 动画效果展开 / 收起 时主按钮旋转 360°,配合渐变颜色变化和文字切换
  • 文字切换:通过伪元素 ::after 实现 “展开”→“收起” 的平滑过渡,避免 DOM 频繁操作
  background: linear-gradient(135deg, #1a237e, #3949ab);
  transition: all 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}
.main-btn.active {
  transform: rotate(360deg);
  background: linear-gradient(135deg, #0d47a1, #1976d2);
}
.main-btn span { opacity: 1; }
.main-btn.active span { opacity: 0; }
.main-btn::after {
  content: "收起";
  position: absolute;
  opacity: 0;
}
.main-btn.active::after { opacity: 1; }

子按钮展开动画

  • 贝塞尔曲线参数:cubic-bezier(0.34, 1.56, 0.64, 1) 模拟弹性效果,前半段加速,后半段减速
.sub-btn { transition: all 0.6s cubic-bezier(0.34, 1.56, 0.64, 1); }

菜单配置

mainBtnText

mainBtnText: {
  expand: "展开",
  collapse: "收起",
}
  • expand:收起状态时主按钮上显示的显示文字

  • collapse:展开状态时主按钮上显示的文字

subBtns

子菜单组,这里简单用 emoji 来做 icon,需要使用 图片svg 的话需要简单改下。

subBtns: [
  { icon: "📅", text: "日程" },
  { icon: "📞", text: "联系" },
  { icon: "📚", text: "文档" },
  { icon: "⚙️", text: "设置" },
  { icon: "🚀", text: "加速" },
  { icon: "💡", text: "反馈" },
  { icon: "📊", text: "统计" },
],

其它

const wheelConfig = {
  …………,
  radius: 120, // 子按钮分布半径
  animationDuration: 0.6, // 动画时长(秒)
  animationEasing: "cubic-bezier(0.34, 1.56, 0.64, 1)", // 弹性动画缓动函数
};

生成子按钮

根据配置信息动态生成子按钮。

子按钮弧度计算

每个子按钮的角度为 360°/子按钮数量×索引

角度转弧度 = 角度 × (π/180)

const btn = document.createElement("li");
btn.className = "sub-btn";
btn.innerHTML = `
  <div class="sub-btn-icon">${item.icon}</div>
  <div class="sub-btn-text">${item.text}</div>
`;
const angle =
  (360 / this.config.subBtns.length) * index * (Math.PI / 180);

子按钮位置计算

转换为弧度后通过 Math.cos()Math.sin() 计算相对位置坐标

const x = Math.cos(angle) * this.config.radius;
const y = Math.sin(angle) * this.config.radius;

btn.style.left = `calc(50% + ${x}px)`;
btn.style.top = `calc(50% + ${y}px)`;

源码

gitee

gitee.com/zheng_yongt…

github

github.com/yongtaozhen…


  • 🌟 觉得有帮助的可以点个 star~
  • 🖊 有什么问题或错误可以指出,欢迎 pr~
  • 📬 有什么想要实现的功能或想法可以联系我~

公众号

关注公众号『 前端也能这么有趣 』,获取更多有趣内容。

发送 加群 还可以加入群聊,一起来学习(摸鱼)吧~

说在后面

🎉 这里是 JYeontu,现在是一名前端工程师,有空会刷刷算法题,平时喜欢打羽毛球 🏸 ,平时也喜欢写些东西,既为自己记录 📋,也希望可以对大家有那么一丢丢的帮助,写的不好望多多谅解 🙇,写错的地方望指出,定会认真改进 😊,偶尔也会在自己的公众号『前端也能这么有趣』发一些比较有趣的文章,有兴趣的也可以关注下。在此谢谢大家的支持,我们下文再见 🙌。