HTML5技术实现的小钢琴

HTML5技术实现的小钢琴

用HTML5实现的小钢琴,按下钢琴键上的相应字母用或用鼠标点击钢琴键发声,源码如下:

html 复制代码
<!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

用浏览器运行效果如下:

你可以用英文状态下按下琴键上的字符,或用鼠标单击琴键试试了。

钢琴演奏中,滑音是通过在音符之间平滑地滑动手指,使音符之间产生连贯的过渡效果。

上面的代码滑动按键能产生了滑音效果,但滑动鼠标不能,现在修改上面程序,使用鼠标都能产生了滑音效果。

修改后源码如下:

html 复制代码
<!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>

请注意,这段代码包含了对鼠标按下、移动和松开,以及键盘按下的事件监听。

你可以在此基础上继续改进优化。

相关推荐
YHL4 分钟前
🎯 Danci —— 用 AI 驱动开发一个全栈英语单词学习平台
前端·后端
平头哥~5 分钟前
Day 20 _ 3D 翻卡_perspective 写错人,卡片就穿帮
前端·3d·css3·学习资料
小聪70814 分钟前
elpis-core 前端 Webpack 工程化实践
前端
2601_9539880714 分钟前
Ricon组态实时监控 - 毫秒级数据可视化
前端·物联网·数学建模·信息可视化·架构·前端框架
V1588972620138 分钟前
从滴滴模式看机器人租赁:撮合型租赁平台开发源码的调度系统设计思路
linux·前端·机器人
szarron1 小时前
国产手持式频谱分析仪选型攻略:TFN RC系列 vs HTOOL SA8T频谱分析仪 专业参数对比(军工/路测/调试全覆盖)
开发语言·前端·状态模式
开开心心就好1 小时前
免费桌签打印工具,支持批量导入名字
前端·javascript·人工智能·docker·jupyter·智能手机·语音识别
涛涛ing1 小时前
2026 年 9 月,整个 npm 生态的「心脏」都被 Rust 换了
前端
IT_陈寒1 小时前
明明设了默认值,为什么我的JavaScript函数参数还是undefined?
前端·人工智能·后端
CappuccinoRose1 小时前
Web Components 基础
前端·javascript·交互·web component·shadow dom