前言
昨天写了一篇 纯 JS + CSS 手搓一个在线节拍器 的文章,主要阐述了一下实现思路,后面又想了一下,感觉好像说了很多,但又好像什么也没说,因为,高手不需要,而新手看了好像也很难因此而直接上手,毕竟 ,咱们自己也常说“Talk is cheep. Show me the code.”。
因此,这篇文章,我干脆直接把源代码从项目中抠出来,然后简化一下贴上来,这样有需要的人直接复制代码本地运行就可以了。简单、直接,不搞弯弯绕让大家自己去悟了!
1. 展示效果
先展示一下节拍器简化后的效果:
简化的目的是为了去掉一些外部依赖,合并代码文件等,但基本思路是一致的。
2. 依赖资源
简化后的代码只需要依赖一个背景图就可以了,下面是我请设计师设计的原创设计图,也一并贡献出来了,供大家学习使用,反正需要的人有的是办法得到。
3. 源代码
一共就三个文件:index.html
, style.css
和 metronome.js
。
3.1 index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Metronome</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div class="metronome-box">
<div class="pendulum">
<input type="range" min="40" max="208" step="1" class="bpm-slider" />
</div>
<div class="bpm-value">60</div>
</div>
<div class="control-btns">
<button class="start-btn">Start</button>
<button class="stop-btn">Stop</button>
</div>
<script src="metronome.js"></script>
</body>
</html>
3.2 style.css
body {
padding: 0;
margin: 0;
background-color: #fff;
}
.metronome-box {
position: relative;
width: 368px;
height: 624px;
margin: 100px auto 0;
background: url("bg.png") no-repeat -120px 0px;
background-size: 487px;
}
.metronome-box .pendulum {
position: absolute;
top: 150px;
left: 161px;
width: 54px;
height: 424px;
overflow: hidden;
background: url("bg.png") no-repeat 3px -170px;
animation: 1s infinite ease-in-out alternate;
background-size: 487px;
animation-delay: -500ms;
transform-origin: 22px 392px;
}
@keyframes pendulum {
0% {
transform: rotate(30deg);
}
100% {
transform: rotate(-30deg);
}
}
.metronome-box .bpm-slider {
-webkit-appearance: none;
appearance: none;
height: 54px;
width: 280px;
transform: rotate(90deg);
transform-origin: right bottom;
background: transparent;
position: absolute;
top: 264px;
left: -288px;
}
.metronome-box .bpm-slider::-webkit-slider-thumb {
-webkit-appearance: none;
height: 54px;
width: 54px;
transform: rotate(-90deg);
background: url("bg.png") no-repeat -38px -73px;
background-size: 487px;
cursor: grabbing;
}
.metronome-box .bpm-value {
position: absolute;
top: 568px;
left: 0;
width: 100%;
text-align: center;
font-size: 32px;
font-weight: bold;
letter-spacing: 4px;
color: rgba(255, 255, 255, 0.25);
}
.control-btns {
display: flex;
justify-content: center;
align-items: center;
gap: 2rem;
margin-top: 20px;
}
.control-btns button {
font-size: 32px;
font-weight: bold;
padding: 5px 10px;
}
3.3 metronome.js
window.addEventListener("load", function () {
const pendulum = this.document.querySelector(".pendulum");
const bpmSlider = this.document.querySelector(".bpm-slider");
const bpmValue = this.document.querySelector(".bpm-value");
const startBtn = this.document.querySelector(".start-btn");
const stopBtn = this.document.querySelector(".stop-btn");
let audioContext;
let gainNode;
let isRunning = false;
let timer;
let duration = Math.round((60 * 1000) / bpmSlider.value);
startBtn.addEventListener("click", function () {
if (isRunning) {
return;
}
pendulum.style.animationDelay = -duration / 2 + "ms";
pendulum.style.animationDuration = duration + "ms";
pendulum.style.animationName = "pendulum";
if (!audioContext) {
audioContext = new AudioContext();
gainNode = audioContext.createGain();
gainNode.connect(audioContext.destination);
}
timer = setInterval(() => {
const oscillator = audioContext.createOscillator();
oscillator.type = "square";
oscillator.frequency.value = 800;
oscillator.connect(gainNode);
oscillator.start();
oscillator.stop(audioContext.currentTime + 0.1);
}, duration);
isRunning = true;
});
stopBtn.addEventListener("click", function () {
if (!isRunning) {
return;
}
pendulum.style.animationName = "none";
clearInterval(timer);
isRunning = false;
});
bpmSlider.addEventListener("input", (e) => {
duration = Math.round((60 * 1000) / bpmSlider.value);
bpmValue.textContent = e.target.value;
});
});
结语
以上就是节拍器的全部代码了,复制下来试试吧,当然,源码我也放到GitHub上了,下载运行可能会更直接。
如果你想要最原汁原味、最真实场景的实现,那就还是 点击这里 查看吧。
评论0
暂时没有评论