HTML5技术实现的小钢琴
用HTML5实现的小钢琴,按下钢琴键上的相应字母用或用鼠标点击钢琴键发声,源码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>用HTML5实现的小钢琴</title>
<style>
.key {
width: 50px;
height: 150px;
border: 1px solid black;
display: inline-block;
margin: 5px;
text-align: center;
line-height: 150px;
cursor: pointer;
position: relative; /* 为了绝对定位伪元素而需要 */
transition: transform 0.1s; /* 按键按下时平滑过渡效果 */
}
/* 当按键被按下时的样式 */
.key.active {
transform: translateY(4px); /* 将按键向下移动 */
}
</style>
</head>
<body>
<div id="A" class="key">A</div>
<div id="S" class="key">S</div>
<div id="D" class="key">D</div>
<div id="F" class="key">F</div>
<div id="G" class="key">G</div>
<div id="H" class="key">H</div>
<div id="J" class="key">J</div>
<div id="K" class="key">K</div>
<script>
// 创建一个新的AudioContext实例,用于处理音频
const audioContext = new (window.AudioContext || window.webkitAudioContext)();
// 播放特定频率的声音
function playSound(frequency) {
const oscillator = audioContext.createOscillator();
oscillator.type = 'sine'; // 选择波形类型,这里是正弦波
oscillator.frequency.setValueAtTime(frequency, audioContext.currentTime); // 设置频率
oscillator.connect(audioContext.destination); // 连接到音频输出
oscillator.start(); // 开始播放
oscillator.stop(audioContext.currentTime + 0.3); // 0.3秒后停止播放
}
// 获取所有的琴键元素
const keys = document.querySelectorAll('.key');
keys.forEach(key => {
// 为每个琴键添加鼠标点击事件
key.addEventListener('click', () => {
playNote(key.textContent); // 播放琴键对应的音符
animatePress(key); // 触发按键动画效果
});
});
// 监听键盘按下事件
document.addEventListener('keydown', (event) => {
const keyName = event.key.toUpperCase(); // 获取按键名并转为大写
const keyElement = document.getElementById(keyName); // 获取对应的琴键元素
if (keyElement) {
playNote(keyName); // 播放琴键对应的音符
animatePress(keyElement); // 触发按键动画效果
}
});
// 触发琴键按下的动画效果
function animatePress(keyElement) {
keyElement.classList.add('active'); // 添加按下状态的样式类
setTimeout(() => {
keyElement.classList.remove('active'); // 在100毫秒后移除按下状态的样式类
}, 100); // 这个时间应该与CSS中的过渡时间一致
}
// 根据音符播放声音
function playNote(note) {
let frequency;
switch (note) {
case 'A':
frequency = 261.63;
break;
case 'S':
frequency = 293.66;
break;
case 'D':
frequency = 329.63;
break;
case 'F':
frequency = 349.23;
break;
case 'G':
frequency = 392.00;
break;
case 'H':
frequency = 440.00;
break;
case 'J':
frequency = 493.88;
break;
case 'K':
frequency = 523.25;
break;
default:
return; // 如果不是琴键对应的字母,则不执行任何操作
}
playSound(frequency); // 调用函数播放声音
}
</script>
</body>
</html>
代码中使用了JavaScript中的箭头函数(Arrow Function)语法。箭头函数是ES6中的一种函数声明方式,它的语法比较简洁。箭头函数的基本格式是:(参数) => {函数体}。
keys.forEach(key => { })
箭头函数的参数是key,表示forEach遍历的每个元素。
key.addEventListener('click', () => { })
它是给每个琴键添加鼠标点击事件的代码。addEventListener 方法用于给元素添加事件监听器。这里添加了一个点击事件的监听器,当用户点击琴键时,箭头函数会被执行。
我对乐理了解很少,相关音高(pitch)请参考这里https://www.autopiano.cn/toolbox/pitch
用浏览器运行效果如下:
你可以用英文状态下按下琴键上的字符,或用鼠标单击琴键试试了。
钢琴演奏中,滑音是通过在音符之间平滑地滑动手指,使音符之间产生连贯的过渡效果。
上面的代码滑动按键能产生了滑音效果,但滑动鼠标不能,现在修改上面程序,使用鼠标都能产生了滑音效果。
修改后源码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>用HTML5实现的小钢琴2</title>
<style>
.key {
width: 50px;
height: 150px;
border: 1px solid black;
display: inline-block;
margin: 5px;
text-align: center;
line-height: 150px;
cursor: pointer;
position: relative;
transition: transform 0.1s;
}
.key.active {
transform: translateY(4px);
}
</style>
</head>
<body>
<div id="A" class="key">A</div>
<div id="S" class="key">S</div>
<div id="D" class="key">D</div>
<div id="F" class="key">F</div>
<div id="G" class="key">G</div>
<div id="H" class="key">H</div>
<div id="J" class="key">J</div>
<div id="K" class="key">K</div>
<script>
const audioContext = new (window.AudioContext || window.webkitAudioContext)();
let isMouseDown = false; // 记录鼠标是否被按下
function playSound(frequency) {
const oscillator = audioContext.createOscillator();
oscillator.type = 'sine';
oscillator.frequency.setValueAtTime(frequency, audioContext.currentTime);
oscillator.connect(audioContext.destination);
oscillator.start();
oscillator.stop(audioContext.currentTime + 0.3);
}
const keys = document.querySelectorAll('.key');
keys.forEach(key => {
key.addEventListener('mousedown', (event) => {
isMouseDown = true; // 设置鼠标按下状态为true
playNoteFromElement(event.target);
});
key.addEventListener('mouseenter', (event) => {
if (isMouseDown) { // 如果鼠标处于按下状态,则播放音符
playNoteFromElement(event.target);
}
});
// 鼠标按下并移动到其他琴键时,无需额外mouseup事件监听
});
// 监听文档的mouseup事件,以处理鼠标在琴键外松开的情况
document.addEventListener('mouseup', () => {
isMouseDown = false;
});
// 监听键盘按下事件
document.addEventListener('keydown', (event) => {
const keyName = event.key.toUpperCase(); // 获取按键名并转为大写
const keyElement = document.getElementById(keyName); // 获取对应的琴键元素
if (keyElement && !keyElement.classList.contains('active')) {
playNoteFromElement(keyElement);
}
});
function playNoteFromElement(element) {
const note = element.textContent;
playNote(note);
animatePress(element);
}
function animatePress(keyElement) {
keyElement.classList.add('active');
setTimeout(() => {
keyElement.classList.remove('active');
}, 100);
}
function playNote(note) {
let frequency;
switch (note) {
case 'A':
frequency = 261.63;
break;
case 'S':
frequency = 293.66;
break;
case 'D':
frequency = 329.63;
break;
case 'F':
frequency = 349.23;
break;
case 'G':
frequency = 392.00;
break;
case 'H':
frequency = 440.00;
break;
case 'J':
frequency = 493.88;
break;
case 'K':
frequency = 523.25;
break;
default:
return;
}
playSound(frequency);
}
</script>
</body>
</html>
请注意,这段代码包含了对鼠标按下、移动和松开,以及键盘按下的事件监听。
你可以在此基础上继续改进优化。