一键生成“水波纹按钮”,连 CSS 动画都不用自己写了!一键生成“水波纹按钮”,连 CSS 动画都不用自己写了!
前两天做页面交互时,突然有个想法:“我想加一个点击时有水波纹的按钮,就像 Android 上那种 Material Ripple 效果,既优雅又带感。”
以前搞这种动画,光是 CSS 和 JS 的交互处理就能折腾一阵子:点击位置的计算、波纹的生成、动画时间、淡出曲线、性能优化……一大堆细节。
但现在,我只在 CodeBuddy 里轻描淡写地说了一句:
“生成一个按钮,点击时有水波纹动画,模仿 Material Design Ripple 效果。”
没想到 CodeBuddy 直接给我整了个现成的,自带动画、自适应点击位置、可复用样式的按钮组件,效果干净、流畅,完全不输手写版本。
我想要的水波纹效果是什么样?
我说的“水波纹”并不是那种浮夸的点击特效,而是 Material Design 里的那种:
-
鼠标点击按钮时,以点击点为中心出现一个淡淡的圆形扩散波纹;
-
波纹会逐渐扩散变大,然后渐隐消失;
-
在不同按钮尺寸下,动画自然适配,不突兀;
-
背景色不被覆盖,波纹只是视觉反馈;
-
不阻塞其他交互,响应足够快。
说白了,就是一种“细腻但克制”的美感。
CodeBuddy 如何“自动生成”这个效果?
CodeBuddy 的能力在于,它不只是理解按钮该长什么样,它还能理解“水波纹”这三个字背后的交互意图。
我只输入一句自然语言指令:
“生成一个按钮,点击时显示水波纹动画,模拟 Material Ripple 效果。”
CodeBuddy 给我的组件非常完整:
-
按钮结构:简洁干净,支持文本、图标或任意子内容;
-
CSS 动画:用
@keyframes
精细模拟波纹扩散和透明度衰减; -
事件逻辑:自动绑定点击事件,根据鼠标点击位置动态生成波纹;
-
性能考虑:波纹元素会在动画结束后自动移除,内存友好;
-
可复用性:生成的是组件化写法,可以多处引用、不重复代码;
-
样式隔离:波纹层与按钮内容分离,保证文字/icon 不被覆盖。
而我,不用动手写一行样式。
点击反馈体验:超出预期的细腻
我原本以为 CodeBuddy 只是给一个基础版,结果效果出奇地丝滑。点击按钮的那一刻,波纹从鼠标点中心扩散开,透明度控制得刚刚好,没有明显的卡顿或突兀。
更惊喜的是——
-
多次快速点击:波纹能正确叠加,不互相遮盖;
-
适配深色背景:波纹颜色会自动调整为浅色调;
-
移动端长按:也能触发波纹,反馈一致;
-
hover 状态:还贴心加了阴影过渡,动静结合。
可以说,这就是标准 UI 体验里“锦上添花”的交互小亮点。
想拓展?CodeBuddy 还能继续自动加料
我试着继续和 CodeBuddy 说:
“加一个变体,支持长按触发水波纹,并显示文字提示。”
CodeBuddy 就自动生成了一个新版本,按钮长按超过 500ms 不但有水波纹,还会在上方弹出一句提示信息,比如:“正在执行,请稍候……”
我又说了一句:
“按钮加图标,放在左边,点击水波纹不遮住图标。”
CodeBuddy 就更新了按钮结构,图标和文字左右排布,并自动让水波纹绕开图标中心,重点落在点击位置。真的是非常智能的补全能力。
CodeBuddy 帮我省下的不只是时间
以前,我总觉得一些交互效果就算好看,可能不值得花一两个小时来写。但现在有了 CodeBuddy ,我只需要几秒钟就能把想法变成现实,还能自动生成质量不错的代码。
从“我想要一个水波纹按钮”,到“这个按钮已经可以上线用了”,只隔着一行自然语言。
这个过程,不仅提升了效率,更释放了我的创造力。因为我再也不会因为“实现起来太麻烦”而放弃一个好点子了。
想试试的朋友可以这样做:
打开 CodeBuddy ,输入这句:
“生成一个按钮,点击时带水波纹动画,模拟 Material Ripple 效果。”
然后看看 CodeBuddy 给你的惊喜。如果你有更复杂的交互想法,也尽管说出来,它都能帮你“对号入座”。未来的前端开发,也许真的不再是写组件,而是说组件。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Material 水波纹动画效果</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Arial', 'Microsoft YaHei', sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 20px;
color: #333;
}
.header {
text-align: center;
margin-bottom: 50px;
color: white;
}
.header h1 {
font-size: 2.5em;
margin-bottom: 10px;
text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
}
.header p {
font-size: 1.1em;
opacity: 0.9;
}
.demo-container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 30px;
max-width: 1200px;
width: 100%;
}
.demo-section {
background: rgba(255, 255, 255, 0.95);
border-radius: 20px;
padding: 30px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
backdrop-filter: blur(10px);
}
.section-title {
font-size: 1.3em;
font-weight: bold;
margin-bottom: 20px;
color: #333;
text-align: center;
}
/* 基础水波纹容器 */
.ripple-container {
position: relative;
overflow: hidden;
cursor: pointer;
user-select: none;
-webkit-tap-highlight-color: transparent;
}
/* 水波纹动画 */
.ripple {
position: absolute;
border-radius: 50%;
background: rgba(255, 255, 255, 0.6);
transform: scale(0);
animation: ripple-animation 0.6s linear forwards;
pointer-events: none;
z-index: 1;
}
@keyframes ripple-animation {
0% {
transform: scale(0);
opacity: 1;
}
100% {
transform: scale(4);
opacity: 0;
}
}
/* 长按水波纹动画 */
.ripple-long-press {
position: absolute;
border-radius: 50%;
background: rgba(255, 255, 255, 0.3);
transform: scale(0);
animation: ripple-long-press-animation 2s ease-out forwards;
pointer-events: none;
z-index: 1;
}
@keyframes ripple-long-press-animation {
0% {
transform: scale(0);
opacity: 0.8;
}
50% {
transform: scale(2);
opacity: 0.6;
}
100% {
transform: scale(4);
opacity: 0;
}
}
/* 基础按钮样式 */
.btn {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 12px 24px;
margin: 10px;
border: none;
border-radius: 8px;
background: #2196f3;
color: white;
font-size: 16px;
font-weight: 500;
transition: all 0.3s ease;
position: relative;
min-width: 120px;
min-height: 48px;
}
.btn:hover {
background: #1976d2;
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(33, 150, 243, 0.4);
}
.btn:active {
transform: translateY(0);
}
/* 图标按钮样式 */
.btn-with-icon {
padding-left: 16px;
padding-right: 24px;
justify-content: flex-start;
gap: 12px;
}
.btn-icon {
font-size: 18px;
z-index: 2;
position: relative;
flex-shrink: 0;
width: 20px;
text-align: center;
}
.btn-text {
z-index: 2;
position: relative;
}
/* 不同颜色的按钮 */
.btn-success {
background: #4caf50;
}
.btn-success:hover {
background: #388e3c;
box-shadow: 0 4px 12px rgba(76, 175, 80, 0.4);
}
.btn-warning {
background: #ff9800;
}
.btn-warning:hover {
background: #f57c00;
box-shadow: 0 4px 12px rgba(255, 152, 0, 0.4);
}
.btn-danger {
background: #f44336;
}
.btn-danger:hover {
background: #d32f2f;
box-shadow: 0 4px 12px rgba(244, 67, 54, 0.4);
}
.btn-secondary {
background: #6c757d;
}
.btn-secondary:hover {
background: #545b62;
box-shadow: 0 4px 12px rgba(108, 117, 125, 0.4);
}
/* 圆形按钮 */
.btn-circle {
width: 56px;
height: 56px;
border-radius: 50%;
padding: 0;
min-width: auto;
font-size: 24px;
}
/* 卡片样式 */
.card {
background: #fff;
border-radius: 12px;
padding: 20px;
margin: 10px 0;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
transition: all 0.3s ease;
}
.card:hover {
transform: translateY(-4px);
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15);
}
/* 长按提示 */
.long-press-tooltip {
position: absolute;
top: -40px;
left: 50%;
transform: translateX(-50%);
background: rgba(0, 0, 0, 0.8);
color: white;
padding: 8px 12px;
border-radius: 4px;
font-size: 12px;
white-space: nowrap;
opacity: 0;
pointer-events: none;
transition: opacity 0.3s ease;
z-index: 10;
}
.long-press-tooltip::after {
content: '';
position: absolute;
top: 100%;
left: 50%;
transform: translateX(-50%);
border: 4px solid transparent;
border-top-color: rgba(0, 0, 0, 0.8);
}
.long-press-tooltip.show {
opacity: 1;
}
/* 进度指示器 */
.progress-indicator {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 4px;
background: rgba(255, 255, 255, 0.3);
border-radius: 2px;
overflow: hidden;
opacity: 0;
transition: opacity 0.3s ease;
}
.progress-bar {
height: 100%;
background: rgba(255, 255, 255, 0.8);
width: 0%;
transition: width linear;
border-radius: 2px;
}
.progress-indicator.show {
opacity: 1;
}
/* 列表项样式 */
.list-item {
display: flex;
align-items: center;
padding: 16px 20px;
margin: 2px 0;
background: #fff;
border-radius: 8px;
cursor: pointer;
transition: background-color 0.3s ease;
}
.list-item:hover {
background: #f5f5f5;
}
.list-icon {
margin-right: 16px;
font-size: 20px;
width: 24px;
text-align: center;
color: #666;
z-index: 2;
position: relative;
}
.list-content {
flex: 1;
z-index: 2;
position: relative;
}
.list-title {
font-weight: 500;
margin-bottom: 4px;
}
.list-subtitle {
font-size: 14px;
color: #666;
}
/* 输入框水波纹 */
.input-container {
position: relative;
margin: 15px 0;
}
.input-field {
width: 100%;
padding: 16px;
border: 2px solid #ddd;
border-radius: 8px;
font-size: 16px;
background: #fff;
transition: border-color 0.3s ease;
outline: none;
}
.input-field:focus {
border-color: #2196f3;
}
/* 开关样式 */
.switch-container {
display: flex;
align-items: center;
justify-content: space-between;
padding: 16px 0;
margin: 10px 0;
}
.switch {
position: relative;
width: 52px;
height: 32px;
background: #ccc;
border-radius: 16px;
cursor: pointer;
transition: background-color 0.3s ease;
}
.switch.active {
background: #2196f3;
}
.switch-thumb {
position: absolute;
top: 2px;
left: 2px;
width: 28px;
height: 28px;
background: white;
border-radius: 50%;
transition: transform 0.3s ease;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}
.switch.active .switch-thumb {
transform: translateX(20px);
}
/* 演示说明 */
.demo-info {
background: #e3f2fd;
border-left: 4px solid #2196f3;
padding: 15px;
margin: 20px 0;
border-radius: 4px;
font-size: 14px;
color: #1565c0;
}
/* 响应式设计 */
@media (max-width: 768px) {
.demo-container {
grid-template-columns: 1fr;
gap: 20px;
}
.header h1 {
font-size: 2em;
}
.demo-section {
padding: 20px;
}
}
/* 自定义水波纹颜色 */
.ripple-blue {
background: rgba(33, 150, 243, 0.6);
}
.ripple-green {
background: rgba(76, 175, 80, 0.6);
}
.ripple-orange {
background: rgba(255, 152, 0, 0.6);
}
.ripple-red {
background: rgba(244, 67, 54, 0.6);
}
.ripple-dark {
background: rgba(0, 0, 0, 0.2);
}
</style>
</head>
<body>
<div class="header">
<h1>🌊 Material 水波纹动画效果</h1>
<p>模拟 Material Design Ripple 效果,支持点击、长按和图标按钮</p>
</div>
<div class="demo-container">
<!-- 基础按钮演示 -->
<div class="demo-section">
<div class="section-title">🎯 基础水波纹按钮</div>
<div class="demo-info">
点击按钮查看水波纹效果,支持多种颜色主题
</div>
<button class="btn ripple-container" data-ripple-color="white">
默认按钮
</button>
<button class="btn btn-success ripple-container" data-ripple-color="white">
成功按钮
</button>
<button class="btn btn-warning ripple-container" data-ripple-color="white">
警告按钮
</button>
<button class="btn btn-danger ripple-container" data-ripple-color="white">
危险按钮
</button>
</div>
<!-- 图标按钮演示 -->
<div class="demo-section">
<div class="section-title">🔘 图标按钮水波纹</div>
<div class="demo-info">
水波纹不会遮挡左侧图标,保持图标清晰可见
</div>
<button class="btn btn-with-icon ripple-container" data-ripple-color="white">
<span class="btn-icon">📁</span>
<span class="btn-text">打开文件</span>
</button>
<button class="btn btn-success btn-with-icon ripple-container" data-ripple-color="white">
<span class="btn-icon">💾</span>
<span class="btn-text">保存文档</span>
</button>
<button class="btn btn-warning btn-with-icon ripple-container" data-ripple-color="white">
<span class="btn-icon">⚙️</span>
<span class="btn-text">设置选项</span>
</button>
<button class="btn btn-danger btn-with-icon ripple-container" data-ripple-color="white">
<span class="btn-icon">🗑️</span>
<span class="btn-text">删除文件</span>
</button>
</div>
<!-- 长按按钮演示 -->
<div class="demo-section">
<div class="section-title">👆 长按水波纹效果</div>
<div class="demo-info">
长按按钮1秒以上触发特殊水波纹效果和提示文字
</div>
<button class="btn ripple-container long-press-btn"
data-ripple-color="white"
data-long-press-text="长按已激活!">
<span class="progress-indicator">
<div class="progress-bar"></div>
</span>
<span class="long-press-tooltip">继续长按激活</span>
长按我试试
</button>
<button class="btn btn-success btn-with-icon ripple-container long-press-btn"
data-ripple-color="white"
data-long-press-text="下载已开始!">
<span class="progress-indicator">
<div class="progress-bar"></div>
</span>
<span class="long-press-tooltip">长按开始下载</span>
<span class="btn-icon">⬇️</span>
<span class="btn-text">长按下载</span>
</button>
<button class="btn btn-danger btn-with-icon ripple-container long-press-btn"
data-ripple-color="white"
data-long-press-text="删除已确认!">
<span class="progress-indicator">
<div class="progress-bar"></div>
</span>
<span class="long-press-tooltip">长按确认删除</span>
<span class="btn-icon">⚠️</span>
<span class="btn-text">长按删除</span>
</button>
</div>
<!-- 圆形按钮演示 -->
<div class="demo-section">
<div class="section-title">⭕ 圆形浮动按钮</div>
<div class="demo-info">
经典的Material Design圆形浮动按钮 (FAB)
</div>
<button class="btn btn-circle ripple-container" data-ripple-color="white">
➕
</button>
<button class="btn btn-success btn-circle ripple-container" data-ripple-color="white">
✓
</button>
<button class="btn btn-warning btn-circle ripple-container" data-ripple-color="white">
⚡
</button>
<button class="btn btn-danger btn-circle ripple-container" data-ripple-color="white">
❌
</button>
</div>
<!-- 卡片和列表演示 -->
<div class="demo-section">
<div class="section-title">📋 交互式列表</div>
<div class="demo-info">
列表项支持水波纹效果,图标不会被遮挡
</div>
<div class="card">
<div class="list-item ripple-container" data-ripple-color="dark">
<div class="list-icon">📧</div>
<div class="list-content">
<div class="list-title">新邮件通知</div>
<div class="list-subtitle">您有3封未读邮件</div>
</div>
</div>
<div class="list-item ripple-container" data-ripple-color="dark">
<div class="list-icon">🔔</div>
<div class="list-content">
<div class="list-title">系统通知</div>
<div class="list-subtitle">软件更新可用</div>
</div>
</div>
<div class="list-item ripple-container" data-ripple-color="dark">
<div class="list-icon">👤</div>
<div class="list-content">
<div class="list-title">用户设置</div>
<div class="list-subtitle">管理您的个人资料</div>
</div>
</div>
</div>
</div>
<!-- 输入框和开关演示 -->
<div class="demo-section">
<div class="section-title">🎛️ 交互控件</div>
<div class="demo-info">
输入框和开关也支持水波纹反馈效果
</div>
<div class="input-container">
<input type="text" class="input-field ripple-container" placeholder="点击输入框查看效果" data-ripple-color="blue">
</div>
<div class="switch-container">
<span>启用通知</span>
<div class="switch ripple-container" data-ripple-color="blue">
<div class="switch-thumb"></div>
</div>
</div>
<div class="switch-container">
<span>深色模式</span>
<div class="switch ripple-container" data-ripple-color="blue">
<div class="switch-thumb"></div>
</div>
</div>
</div>
</div>
<script>
class MaterialRipple {
constructor() {
this.longPressTimer = null;
this.longPressDelay = 1000; // 长按延迟时间
this.init();
}
init() {
// 为所有水波纹容器添加事件监听
document.addEventListener('click', this.handleClick.bind(this));
document.addEventListener('mousedown', this.handleMouseDown.bind(this));
document.addEventListener('mouseup', this.handleMouseUp.bind(this));
document.addEventListener('mouseleave', this.handleMouseLeave.bind(this));
// 触摸事件支持
document.addEventListener('touchstart', this.handleTouchStart.bind(this));
document.addEventListener('touchend', this.handleTouchEnd.bind(this));
document.addEventListener('touchcancel', this.handleTouchCancel.bind(this));
// 开关特殊处理
this.initSwitches();
}
// 处理点击事件
handleClick(e) {
const container = e.target.closest('.ripple-container');
if (!container) return;
// 开关特殊处理
if (container.classList.contains('switch')) {
this.toggleSwitch(container);
}
this.createRipple(e, container);
}
// 处理鼠标按下
handleMouseDown(e) {
const container = e.target.closest('.long-press-btn');
if (!container) return;
this.startLongPress(e, container);
}
// 处理鼠标释放
handleMouseUp(e) {
this.endLongPress();
}
// 处理鼠标离开
handleMouseLeave(e) {
this.endLongPress();
}
// 处理触摸开始
handleTouchStart(e) {
const container = e.target.closest('.long-press-btn');
if (!container) return;
// 创建模拟的鼠标事件对象
const touch = e.touches[0];
const mouseEvent = {
clientX: touch.clientX,
clientY: touch.clientY,
target: e.target
};
this.startLongPress(mouseEvent, container);
}
// 处理触摸结束
handleTouchEnd(e) {
this.endLongPress();
}
// 处理触摸取消
handleTouchCancel(e) {
this.endLongPress();
}
// 创建水波纹效果
createRipple(e, container, isLongPress = false) {
const rect = container.getBoundingClientRect();
const size = Math.max(rect.width, rect.height);
const x = e.clientX - rect.left - size / 2;
const y = e.clientY - rect.top - size / 2;
const ripple = document.createElement('div');
ripple.className = isLongPress ? 'ripple-long-press' : 'ripple';
// 设置水波纹颜色
const rippleColor = container.dataset.rippleColor;
if (rippleColor) {
ripple.classList.add(`ripple-${rippleColor}`);
}
ripple.style.width = ripple.style.height = size + 'px';
ripple.style.left = x + 'px';
ripple.style.top = y + 'px';
// 如果是图标按钮,确保水波纹不遮挡图标
if (container.classList.contains('btn-with-icon')) {
const icon = container.querySelector('.btn-icon');
if (icon) {
const iconRect = icon.getBoundingClientRect();
const containerRect = container.getBoundingClientRect();
const iconRelativeX = iconRect.left - containerRect.left;
const iconRelativeY = iconRect.top - containerRect.top;
// 调整水波纹起始位置,避开图标区域
if (e.clientX - rect.left < iconRelativeX + iconRect.width + 10) {
ripple.style.left = (iconRelativeX + iconRect.width + 5) + 'px';
}
}
}
container.appendChild(ripple);
// 动画完成后移除水波纹元素
setTimeout(() => {
if (ripple.parentNode) {
ripple.parentNode.removeChild(ripple);
}
}, isLongPress ? 2000 : 600);
}
// 开始长按检测
startLongPress(e, container) {
const tooltip = container.querySelector('.long-press-tooltip');
const progressIndicator = container.querySelector('.progress-indicator');
const progressBar = container.querySelector('.progress-bar');
// 显示提示和进度条
if (tooltip) tooltip.classList.add('show');
if (progressIndicator) progressIndicator.classList.add('show');
// 重置进度条
if (progressBar) {
progressBar.style.transition = `width ${this.longPressDelay}ms linear`;
progressBar.style.width = '100%';
}
this.longPressTimer = setTimeout(() => {
this.triggerLongPress(e, container);
}, this.longPressDelay);
}
// 结束长按检测
endLongPress() {
if (this.longPressTimer) {
clearTimeout(this.longPressTimer);
this.longPressTimer = null;
}
// 隐藏所有长按相关元素
document.querySelectorAll('.long-press-tooltip.show').forEach(tooltip => {
tooltip.classList.remove('show');
});
document.querySelectorAll('.progress-indicator.show').forEach(indicator => {
indicator.classList.remove('show');
const progressBar = indicator.querySelector('.progress-bar');
if (progressBar) {
progressBar.style.transition = 'width 0.3s ease';
progressBar.style.width = '0%';
}
});
}
// 触发长按事件
triggerLongPress(e, container) {
// 创建长按水波纹
this.createRipple(e, container, true);
// 显示长按文字提示
const longPressText = container.dataset.longPressText;
if (longPressText) {
this.showToast(longPressText);
}
// 隐藏提示元素
this.endLongPress();
// 触发自定义长按事件
const longPressEvent = new CustomEvent('longpress', {
detail: { element: container, originalEvent: e }
});
container.dispatchEvent(longPressEvent);
}
// 初始化开关
initSwitches() {
document.querySelectorAll('.switch').forEach(switchEl => {
switchEl.addEventListener('longpress', (e) => {
console.log('开关长按事件触发');
});
});
}
// 切换开关状态
toggleSwitch(switchEl) {
switchEl.classList.toggle('active');
}
// 显示消息提示
showToast(message) {
// 移除已存在的提示
const existingToast = document.querySelector('.toast');
if (existingToast) {
existingToast.remove();
}
const toast = document.createElement('div');
toast.className = 'toast';
toast.textContent = message;
toast.style.cssText = `
position: fixed;
top: 20px;
right: 20px;
background: rgba(0, 0, 0, 0.8);
color: white;
padding: 15px 20px;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
transform: translateX(400px);
transition: transform 0.3s ease;
z-index: 10000;
font-size: 14px;
max-width: 300px;
`;
document.body.appendChild(toast);
// 显示动画
setTimeout(() => {
toast.style.transform = 'translateX(0)';
}, 100);
// 自动隐藏
setTimeout(() => {
toast.style.transform = 'translateX(400px)';
setTimeout(() => {
if (toast.parentNode) {
toast.parentNode.removeChild(toast);
}
}, 300);
}, 3000);
}
}
// 自定义事件监听示例
document.addEventListener('longpress', (e) => {
console.log('长按事件触发:', e.detail.element);
// 可以根据不同按钮执行不同操作
const element = e.detail.element;
if (element.textContent.includes('下载')) {
console.log('开始下载文件...');
} else if (element.textContent.includes('删除')) {
console.log('确认删除操作...');
}
});
// 页面加载完成后初始化
document.addEventListener('DOMContentLoaded', () => {
new MaterialRipple();
// 添加一些演示交互
document.querySelectorAll('.list-item').forEach(item => {
item.addEventListener('click', () => {
const title = item.querySelector('.list-title').textContent;
console.log(`点击了列表项: ${title}`);
});
});
// 输入框聚焦效果
document.querySelectorAll('.input-field').forEach(input => {
input.addEventListener('focus', () => {
input.parentElement.style.transform = 'scale(1.02)';
});
input.addEventListener('blur', () => {
input.parentElement.style.transform = 'scale(1)';
});
});
});
// 键盘快捷键支持
document.addEventListener('keydown', (e) => {
if (e.key === 'Enter' && e.target.classList.contains('ripple-container')) {
// 模拟点击事件
const clickEvent = new MouseEvent('click', {
clientX: e.target.offsetLeft + e.target.offsetWidth / 2,
clientY: e.target.offsetTop + e.target.offsetHeight / 2,
bubbles: true
});
e.target.dispatchEvent(clickEvent);
}
});
</script>
</body>
</html>
- 点赞
- 收藏
- 关注作者
评论(0)