JS30 - 01 JavaScript Drum Kit

01 JavaScript Drum Kit

效果展示

通过按键来播放音频及改样式。

相关知识

  1. <kbd>标签:定义键盘文本,表示文本是从键盘上键入的。将产生一个行内元素,以浏览器的默认 monospace 字体显示。

  2. data-* 属性:

    • HTML5 新增

    • custom data attributes;赋予我们在所有 HTML 元素上嵌入自定义数据属性的能力,并可以通过脚本在 HTMLDOM 表现之间进行专有数据的交换

    • 属性名不包含大写字母

  3. querySelector() 方法:

    • 接收一个CSS选择符,返回与该模式匹配的第一个元素,如果没有找到匹配的元素,返回null
    • querySelector() 获取静态集合,获取到元素之后就和 html 中的这个元素没有关系了。即只要不再取一次,则维持原来内容、不变
    • getElementBy*() 获取动态集合,每一次在 Javascript 函数中使用这个变量的时候都会再去访问一下这个变量对应的 html 元素
  4. 立即函式 (function() {})();

  5. classList 属性:

    • 返回元素的类名,作为 DOMTokenList 对象

    • <div>元素添加 class:

      document.getElementById("myDIV").classList.add("mystyle");

  6. currentTime 属性:

    • 设置或返回视频播放的当前位置;当设置该属性时,播放会跳跃到指定的位置
    • 设置为 0 可以让例子里的音频连续播放
  7. addEventListener() 方法:

    • document.addEventListener(event, function, useCapture)
    • 当 event 为 transitionend 时,表示该事件在 CSS 完成过渡后触发
  8. forEach() 方法:

    • 用于调用数组的每个元素,并将元素传递给回调函数
  9. currentTarget 事件属性:返回其监听器触发事件的节点,即当前处理该事件的元素、文档或窗口。

代码展示

思路

style.css

html {
    font-size: 10px;
    background: url(img/stars.jpg);
    background-size: cover;
}

body, html {
    margin: 0;
    padding: 0;
    font-family: sans-serif;
}

.keys {
    display: flex;
    flex: 1;
    justify-content: center;
    align-items: center;
    min-height: 100vh;
}

.key {
    margin: 1rem;
    padding: 1rem .5rem;
    width: 10rem;
    color: white;
    text-align: center;
    text-shadow: 0 0 .5rem black;
    font-size: 1.5rem;
    background: rgba(0,0,0,0.4);
    border: .4rem solid black;
    border-radius: .5rem;
    transition: all .07s ease;
}

.playing {
    border-color: #ffc600;
    box-shadow: 0 0 1rem #ffc600;
    transform: scale(1.1);
}

kbd {
    display: block;
    font-size: 4rem;
}

.sound {
    font-size: 1.2rem;
    color: #ffc600;
    text-transform: uppercase;
    letter-spacing: .1rem;
}

index.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="style.css">
</head>

<body>

    <div class="keys">
        <div data-key="65" class="key">
            <kbd>A</kbd>
            <span class="sound">clap</span>
        </div>
        <div data-key="83" class="key">
            <kbd>S</kbd>
            <span class="sound">hihat</span>
        </div>
        <div data-key="68" class="key">
            <kbd>D</kbd>
            <span class="sound">kick</span>
        </div>
        <div data-key="70" class="key">
            <kbd>F</kbd>
            <span class="sound">openhat</span>
        </div>
        <div data-key="71" class="key">
            <kbd>G</kbd>
            <span class="sound">boom</span>
        </div>
        <div data-key="72" class="key">
            <kbd>H</kbd>
            <span class="sound">ride</span>
        </div>
        <div data-key="74" class="key">
            <kbd>J</kbd>
            <span class="sound">snare</span>
        </div>
        <div data-key="75" class="key">
            <kbd>K</kbd>
            <span class="sound">tom</span>
        </div>
        <div data-key="76" class="key">
            <kbd>L</kbd>
            <span class="sound">tink</span>
        </div>
    </div>

    <audio data-key="65" src="sounds/clap.wav"></audio>
    <audio data-key="83" src="sounds/hihat.wav"></audio>
    <audio data-key="68" src="sounds/kick.wav"></audio>
    <audio data-key="70" src="sounds/openhat.wav"></audio>
    <audio data-key="71" src="sounds/boom.wav"></audio>
    <audio data-key="72" src="sounds/ride.wav"></audio>
    <audio data-key="74" src="sounds/snare.wav"></audio>
    <audio data-key="75" src="sounds/tom.wav"></audio>
    <audio data-key="76" src="sounds/tink.wav"></audio>

    <script>
        (function () {

            function playSound(e) {
                // data-key 后的 keyCode 别忘记加引号
                const audio = document.querySelector('audio[data-key="' + e.keyCode + '"]');
                // ES6 写法
                const key = document.querySelector(`div[data-key="${e.keyCode}"]`);

                if (audio) {
                    audio.currentTime = 0;
                    audio.play();
                }
                if (key)
                    key.classList.add("playing");
            }

            function removeTransition(e) {
                // 查看 propertyName
                // console.log(e);

                // 在这个页面中,发生 transition 的样式属性有多个(box-shadow, transform, border-color),所以需要添加一个判断语句,使每发生一次按键事件时,只去除一次样式。下方代码中 transform 也可改为 border-left-color 等。
                if (e.propertyName === 'transform') {
                    e.currentTarget.classList.remove('playing');
                }
            }

            window.addEventListener('keydown',
                // function (e) {
                //     console.log(e.keyCode);
                // }
                playSound);
            document.querySelectorAll('.key').forEach(function (key) {
                key.addEventListener('transitionend', removeTransition);
            });

        })();
    </script>
</body>

</html>

参考

(0)

相关推荐