原生 js 实现鼠标滑过播放音符

本文使用原生jsAudioContext接口实现一个划过菜单播放天空之城的鼠标特效。

概念说明

  • AudioContext接口表示由链接在一起的音频模块构建的音频处理图,每个模块由一个AudioNode表示。音频上下文控制它包含的节点的创建和音频处理或解码的执行。简单地说AudioContext创建了一条无限长的时间轴,时间轴上分布着声音信息(可以理解为频谱),并且不可以停止。我们可以通过时间点改编这些信息,从而控制频率、音色等等。

  • 按照第一国际音高,从低8dao,到高8dao的频率约等于(加粗标出了基准点)[130,147,165,175,196,220,246,262,294,330,349,392,440,494,523,587,659,698,784,880,988,1047]

使用方法

复制下方代码到自己的js文件,修改target为对应的元素选择器即可。

(function (AudioContext) {

    if (!AudioContext) {
        return
    }

    var target = '.menu li' // 设置触发音乐的元素选择器

    var notes = '♪ ♩ ♫ ♬ ¶ ‖ ♭ ♯ § ∮'.split(' ')
    var sheet = '880 987 1046 987 1046 1318 987 659 659 880 784 880 1046 784 659 659 698 659 698 1046 659 1046 1046 1046 987 698 698 987 987 880 987 1046 987 1046 1318 987 659 659 880 784 880 1046 784 659 698 1046 987 1046 1174 1174 1174 1046 1046 880 987 784 880 1046 1174 1318 1174 1318 1567 1046 987 1046 1318 1318 1174 784 784 880 1046 987 1174 1046 784 784 1396 1318 1174 659 1318 1046 1318 1760 1567 1567 1318 1174 1046 1046 1174 1046 1174 1567 1318 1318 1760 1567 1318 1174 1046 1046 1174 1046 1174 987 880 880 987 880'.split(' ')

    var ctx, dom, i = 0, play = function (ev) {
        if (dom) {
            return
        }

        // 播放音节
        sheet[i] || (i = 0)
        ctx || (ctx = new AudioContext())
        var c = ctx.createOscillator(),
            l = ctx.createGain(),
            m = ctx.createGain()
        c.connect(l)
        l.connect(m)
        m.connect(ctx.destination)
        m.gain.setValueAtTime(1, ctx.currentTime)
        c.type = 'sine'
        c.frequency.value = sheet[i++]
        l.gain.setValueAtTime(0, ctx.currentTime)
        l.gain.linearRampToValueAtTime(1, ctx.currentTime + 0.01)
        c.start(ctx.currentTime)
        l.gain.exponentialRampToValueAtTime(0.001, ctx.currentTime + 1)
        c.stop(ctx.currentTime + 1)

        // 显示音符
        var x = ev.pageX,
            y = ev.pageY - 5,
            d = Math.round(7 * Math.random())
        dom = document.createElement('b')
        dom.textContent = notes[d]
        dom.style.zIndex = '99999'
        dom.style.top = y - 100 + 'px'
        dom.style.left = x + 'px'
        dom.style.position = 'absolute'
        dom.style.color = '#FF6EB4'
        document.body.appendChild(dom)
        dom.animate([{ top: y + 'px' }, { opacity: 0 }], { duration: 500 })
        setTimeout(() => {
            dom.remove(), dom = null
        }, 500)

        // 阻止冒泡
        ev.stopPropagation()
    }

    document.querySelectorAll(target).forEach(function (el) {
        el.addEventListener('mouseenter', play)
    })

})(window.AudioContext || window.webkitAudioContext)

特别注意

由于浏览器限制,AudioContext组件需要用户先点击下页面才可以实现自动播放。

参考链接

https://developer.mozilla.org/zh-CN/docs/Web/API/AudioContext

文章作者: 若海; 原文链接: https://www.rehiy.com/post/472/; 转载需声明来自技术写真 - 若海

添加新评论