likes
comments
collection
share

用 HTML5实战打击乐Demo 虚拟类应用开发你真的掌握吗?

作者站长头像
站长
· 阅读数 10

序言

我还记得初中时候很喜欢玩一款游戏叫别踩白块,通过点击黑块来发出声音并且每个不同得黑块有不同的音调串联起来模拟歌曲得弹奏很有意思。然后到现在更新迭代了一大批更高级得音游,那么这些音游如果放在PC端是不是也可以通过敲击键盘来实现打击乐得效果呢?所以今天我们就通过使用HTML5里的一些新特性来实现虚拟类应用开发——打击乐,开始前我们先来看看这个打击乐得效果:

接下来我会为大家详细地讲述本次实战的过程。首先就是给HTML页面编写实现元素添加和框架搭建,然后编写CSS文件给这些元素添加样式,最后再编写JS文件实现事件与元素与操作的交互(元素的动态效果和动作反馈)。

准备工作

首先我们需要准备九个打击乐的音效和一张背景图,大家如果没有的话可以去我的国内Gitee仓库中下载

记得给博主仓库点个收藏哦3q♥

用 HTML5实战打击乐Demo 虚拟类应用开发你真的掌握吗?

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>
    <link rel="stylesheet" href="./common.css">
</head>
<body>
    <div class="keys">
        <div class="key" data-key="65">
            <div>A</div>
            <span class="sound">clap</span>
        </div>
        <div class="key" data-key="83">
            <div>S</div>
            <span class="sound">hihat</span>
        </div>
        <div class="key" data-key="68">
            <div>D</div>
            <span class="sound">kick</span>
        </div>
        <div class="key" data-key="70">
            <div>F</div>
            <span class="sound">openhat</span>
        </div>
        <div class="key" data-key="71">
            <div>G</div>
            <span class="sound">boom</span>
        </div>
        <div class="key" data-key="72">
            <div>H</div>
            <span class="sound">ride </span>
        </div>
        <div class="key" data-key="74">
            <div>J</div>
            <span class="sound">snare</span>
        </div>
        <div class="key" data-key="75">
            <div>K</div>
            <span class="sound">tom</span>
        </div>
        <div class="key" data-key="76">
            <div>L</div>
            <span class="sound">tink</span>
        </div>
    </div>
    <audio src="./sounds/clap.wav" data-key="65"></audio>
    <audio src="./sounds/hihat.wav" data-key="83"></audio>
    <audio src="./sounds/kick.wav" data-key="68"></audio>
    <audio src="./sounds/openhat.wav" data-key="70"></audio>
    <audio src="./sounds/boom.wav" data-key="71"></audio>
    <audio src="./sounds/ride.wav" data-key="72"></audio>
    <audio src="./sounds/snare.wav" data-key="74"></audio>
    <audio src="./sounds/tom.wav" data-key="75"></audio>
    <audio src="./sounds/tink.wav" data-key="76"></audio>
    <script>
        function playSound(e){
            // console.log(e.keyCode);
            const keyCode = e.keyCode;
            // 标签的数据属性
            const key = document.querySelector(
                `.key[data-key="${keyCode}"]`  
            )
            key.classList.add('playing');

            const audio = document.querySelector(
                `audio[data-key="${keyCode}"]`
            )
            if(audio){
                audio.currentTime = 0
                audio.play()
            }
        //    audio && audio.currentTime = 0
        //    audio && audio.play()
            // setTimeout(() =>{
            //     key.classList.remove('playing')
            // },100)
        }
        const keys = Array.from(document.querySelectorAll('.key'))
        console.log(keys);
        keys.forEach(key => {
            // 事件一定要一个个元素的加
            key.addEventListener('transitionend',function(e){
                // console.log(e);
                // console.log(e.propertyName);
                if(e.propertyName !== 'transform') return ;
                this.classList.remove('playing');
            })
        })
        window.addEventListener('keydown',playSound)
    </script>

</body>
</html>

框架构建

首先我们的页面其实很简单,在页面中心有九个元素,并且每个元素中有两个块级元素,上面是键盘字母,下面的对应的音效名称。所以我们可以创建一个大的div盒子来装所有的keys,然后创建九个div样式的子容器,分别在这九个子容器里还有一个div元素存放字母,一个span元素存放对应音效的描述。每个div子容器还需分别添加一个副类名来单独编辑,因为我们后面要利用对应键的key来捕获状态,所以我们给每个键盘字母添加上一个副类名:data-key,值就为这个键盘字母对应的key值,然后我们再将九个音频添加到HTML文件中,将每个音频元素与一个特定的按键码关联起来。

这里我们将JS直接在HTML文件中编写,在最后我会来解释下中的代码

到这里我们的框架就编写完了,下一步我们需要对这些元素进行样式添加。

CSS

/* douban 国内最强前端团队 所有 CSS reset  */
/* 性能不好    
{
    margin: 0;
    padding: 0;
} 
*/
/* CSS Reset */
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed, 
figure, figcaption, footer, header, hgroup, 
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
    margin: 0;
    padding: 0;
    border: 0;
    font-size: 100%;
    font: inherit;
    vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure, 
footer, header, hgroup, menu, nav, section {
    display: block;
}
body {
    line-height: 1;
}
ol, ul {
    list-style: none;
}
blockquote, q {
    quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
    content: '';
    content: none;
}
table {
    border-collapse: collapse;
    border-spacing: 0;
}
/* 业务样式 */
html{
    height: 100vh;
    font-size: 10px;
    background: url('./background.jpg')bottom center;
    background-size: cover;
}
body,html{
    font-family: sans-serif;
}
.keys{
    /* 水平垂直居中 */
    display: flex;
    align-items: center; /*主轴水平居中*/
    justify-content: center; /*纵轴水平居中*/
    min-height: 100vh;
}
.key{
    /* rem —— 最好的适配 PC IPAD PHONE
        rem 相对html根元素 font-size: 10px; 1rem = 10px    
    */
    /* 蓝湖 10px 方便计算*/
    border: .4rem solid #000;
    border-radius: .5rem;
    margin: 1rem;
    font-size: 1.5rem;
    padding: 1rem .5rem;
    /* animation 的简版 ,过渡动画 all 只要这个元素的任何一个样式改变了,运用这个过渡动画 */
    transition: all .07s ease;
    width: 10rem;
    text-align: center;
    color: white;
    text-shadow: 0 0 .5rem black;
}

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

.key div{
    font-size: 4rem;
}

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

新手编写CSS重置样式的时候可能会直接对全局设置 margin: 0padding: 0,这时候我们得提一下豆瓣网站的页面编写,他被称为国内最强的前端团队,我们先来打开豆瓣官网查看一下豆瓣界面是如何对页面进行重置样式编写的,接着我再给大家解释这么写的原因。

用 HTML5实战打击乐Demo 虚拟类应用开发你真的掌握吗?

CSS重置全局样式的选取

当我们进行重置样式编写选择重置特定标签的样式而不是直接对全局设置 margin: 0padding: 0 有下面几个原因:

  1. 精确性和避免副作用:

    • 通过选择特定标签进行样式重置,可以更加精确地控制样式的影响范围,避免对所有元素产生不必要的副作用。
    • 全局设置可能会影响到一些浏览器默认样式以及其他第三方库或组件,可能导致一些不希望的样式冲突。
  2. 保留浏览器默认样式:

    • 有时候,保留一些浏览器默认样式是有意义的。对某些元素应用样式重置,可以确保这些元素在各种浏览器中都有一致的外观。
  3. 性能优化:

    • 将样式重置限制在特定标签上,可以减少样式规则的数量,从而提高性能。全局设置可能会对页面中的所有元素产生影响,导致样式计算和渲染的性能开销增加。
  4. 易维护性:

    • 在大型项目中,选择特定标签进行样式重置可以提高代码的可维护性。如果以后需要调整样式,只需修改特定标签的样式,而不是修改全局样式规则。

总体来说,选择性地对特定标签进行样式重置是一种良好的实践,可以帮助确保页面样式的一致性,并避免潜在的问题和冲突。

代码解释

这段 CSS 代码是对为了对我们的元素样式进行一个美化设置,其中也包括了一些用于重置浏览器默认样式(CSS reset)和业务样式的规则。

  1. CSS Reset:

    • 对一些常见的 HTML 元素应用了基本的样式重置,包括去除边框、设置字体大小为 100%、继承字体样式等,这样可以确保我们的CSS性能能更好。
  2. HTML5 Display-role Reset:

    • 这里我们对一些 HTML5 新增的元素的默认样式进行重置 ,这样做是为了确保它们在老版本的浏览器中也有正确的显示角色。
  3. 业务样式:

    • html 元素设置了高度为视口高度的 100%,字体大小为 10px,背景图为 './background.jpg',使用 cover 属性让背景图片充满整个视口,并在底部居中显示。
    • bodyhtml 设置了通用字体为 sans-serif。
  4. .keys:

    • 让我们的9个子容器实现弹性布局,编写代码时尽量在display: flex;后面紧跟着编写需要如何进行弹性布局的样式编写。弹性布局编写完后再编写其他样式比如min-height: 100vh;
  5. .key:

    • 用来设置单个键盘按键的样式,这里我们设置了每个键盘按键的边框、边框圆角、内外边距、字体大小、居中等属性。
    • 使用 transition 属性实现简单的过渡动画,当键被按下时,通过添加 .playing 类,触发缩放、边框颜色和阴影的变化,以创建视觉效果。简单介绍一下transition 属性,他就相当于animation 的简版 ,实现过渡动画,并且all这个属性代表,只要这个元素的任何一个样式改变了,我们就调用这个过渡动画。在后续文章中我会对此进行详细介绍,让我们接着看下面的解释。
  6. .playing:

    • transform: scale(1.1);:这个属性用于对元素应用缩放变换。在这种情况下,具有类别"playing"的元素将被放大到原始大小的1.1倍,用于
    • border-color: #ffc600;:这个属性将具有类别"playing"的元素的边框颜色设置为黄色(#ffc600)。
    • box-shadow: 0 0 1rem #ffc600;:这个属性向元素添加一个框阴影。值"0 0 1rem"定义了阴影的水平和垂直偏移,如果只设置两个值就代表“上下”和“左右”这里我们只设置了三个值就代表"上0"、"左右0"、"下1rem","1rem"定义了阴影的模糊半径,它是相对于html文件根元素的fz的十倍,在编写CSS基本会选择用rem来设置大小而不是直接px,因为这样不仅利于计算,而且很好地适配不同机型。最后阴影的颜色被设置为黄色(#ffc600)。

这个样式实现的就是,当一个元素具有"playing"类别时,它将以较大的尺寸显示,具有黄色边框,并带有相同黄色的框阴影。

  1. .sound:

    • font-size: 1.2rem;:这个属性设置具有"sound"类别的元素的字体大小为1.2个根元素的字体大小,在这里也就是12px
    • text-transform: uppercase;:这个属性将具有"sound"类别的元素的文本转换为大写字母。
    • letter-spacing: normal;:这个属性将具有"sound"类别的元素的字母间距设置为正常。
    • color: #ffc600;:这个属性设置具有"sound"类别的元素的文本颜色为黄色(#ffc600)。

这段样式实现的效果就是,当一个元素具有"sound"类别时,它将以1.2倍于根元素字体大小的字体大小显示,文本将转换为大写字母,字母间距为正常,并且文本颜色为黄色。

JS

我们这段JS代码不是很长直接放在了HTML中,但是在实际开发过程中请不要模仿我这种写法,因为任务分工明确很重要,不仅是一个文件做一件事,而且一个效果封装到一个选择器中也是如此,这样方便代码的复用而且利于后续根据需求进行修改和和调整等等也会大大增加容错率。

function playSound(e){
            const keyCode = e.keyCode;
            // 标签的数据属性
            const key = document.querySelector(
                `.key[data-key="${keyCode}"]`  
            )
            key.classList.add('playing');

            const audio = document.querySelector(
                `audio[data-key="${keyCode}"]`
            )
            if(audio){
                audio.currentTime = 0
                audio.play()
            }
        }
        const keys = Array.from(document.querySelectorAll('.key'))
        keys.forEach(key => {
            // 事件一定要一个个元素的加
            key.addEventListener('transitionend',function(e){
                // console.log(e);
                // console.log(e.propertyName);
                if(e.propertyName !== 'transform') return ;
                this.classList.remove('playing');
            })
        })
        window.addEventListener('keydown',playSound)

代码解释

  • function playSound(e) { ... }: 这是一个用于播放声音的函数。它接收一个事件对象 e,该对象包含有关按键事件的信息。

  • const keyCode = e.keyCode;: 通过 keyCode 属性获取按下的键的键码。

  • const key = document.querySelector('.key[data-key="${keyCode}"]');: 使用键码选择对应的带有特定数据属性(data-key)的 .key 元素。

  • key.classList.add('playing');: 向选定的键元素添加 'playing' 类,触发 CSS 样式中定义的动画效果。

  • const audio = document.querySelector('audio[data-key="${keyCode}"]');: 使用键码选择对应的带有特定数据属性的 <audio> 元素。

  • if (audio) { audio.currentTime = 0; audio.play(); }: 如果找到相应的音频元素,将音频的当前时间设置为0(以确保每次按下键时都从头播放),然后播放音频。

  • const keys = Array.from(document.querySelectorAll('.key'));: 获取所有带有类别 .key 的元素,并将其转换为一个数组。

  • keys.forEach(key => { ... }: 对每个键元素应用以下事件监听器:

  • key.addEventListener('transitionend', function(e) { ... }: 当 CSS 过渡结束时触发的事件监听器。

  • if (e.propertyName !== 'transform') return;: 如果过渡属性不是 'transform',则退出函数。

  • this.classList.remove('playing');: 从当前键元素中移除 'playing' 类,以便移除过渡效果。

  • window.addEventListener('keydown', playSound);: 向整个窗口添加按键事件监听器,当按键被按下时,调用 playSound 函数。

总结

在了解了HTML5新特性的使用和功能后,页面中能够轻松实现更为高级的功能,经过这一次Demo实战发现样式的编写其实很简单,我们要着重训练的是搭建一个好的框架以及JS文件编写利用好这些新功能,在原本基础上使页面效果实现理想中的样子就可以啦。

创作不易,如果感觉文章对你有帮助的话,点个赞吧♥