「《奇迹再现》专属音乐播放器🎵」致以跃动的心与阳光

简介: 「《奇迹再现》专属音乐播放器🎵」致以跃动的心与阳光

前言


这篇文章的产生有两个原因:


第一个是我在「canvas」国庆将至🇨🇳,"手绘"一幅那兔,并畅谈我的梦中搞了一个彩蛋,彩蛋的标题是:献给寒草未来的爱人,再加上我最近看到了很多代码写的三行情书,就像这种:


#倘若你回首看看我
ifyou.turn_round_aguang():
#我永远在你背后
I.behind(you).forever()
#关注着你
see(you)


于是乎我就萌生了一个想法,就是讲一讲程序员如何表白,后来想起来,老朽并没有这种经历,我咋给大家讲嘛,而且我在搜索如何用程序表白的时候发现很多人回答是:


大直男才用程序表白


我瞬间自闭,就打算放弃这个主题。


还有一件事就是我前一阵写了一个小太阳自娱自乐:


网络异常,图片无法展示
|


但是我有个遗憾,就是太阳的光芒太单调,希望他加入一些动感。


于是我心生一计,将两个主题合二为一,快,叫我小天才!


蹩脚的设计之路


其实这个 demo 的主题已经明确了:


  • 具有表白能力
  • 有动感的小太阳


那么如何搞一个有动感的小太阳呢,我首先想到的就是音乐播放器的动效,就像网易云的这个咚次哒次的效果


网络异常,图片无法展示
|


我就把样式搞的更像太阳就好了。


那具有表白能力咋搞啊,我也不太会设计这方面的东西,我就先搞了一个心❤️(其实是之前试验web-components的时候做的),代码写都写了,即使再短我也要复用一下的!那么心和太阳怎么结合呢? 我陷入了痛苦,常考后,心生一计:


用那个心做按钮吧,点完了开始播放音乐(我这个想法真的是太土鳖了哈哈哈哈哈,但是我会想办法让这个想法不那么土鳖)


实现 📖


音乐处理 🎵


参考MDN:developer.mozilla.org/zh-CN/docs/…


let audio = new Audio("dijia.mp3");
let audioCtx = new (window.AudioContext || window.webkitAudioContext)();
let source = audioCtx.createMediaElementSource(audio)
let analyser = audioCtx.createAnalyser();
source.connect(analyser);
analyser.connect(audioCtx.destination)
analyser.fftSize = 1024;
let bufferLength = analyser.frequencyBinCount;
let dataArray = new Uint8Array(bufferLength);
audio.play();
setInterval(() => {
  analyser.getByteTimeDomainData(dataArray);
  // 这里的dataArray就是我要的信息
  dataArray.slice(0, 360).forEach((item, index) => {
    rays[index].style.height = `${item / 2}px`;
  })
}, 1000)


跳跃的心 ❤️


网络异常,图片无法展示
|


这里用的 web-component


<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>web-component</title>
</head>
<body>
  <my-heart></my-heart>
  <template id="my-heart">
    <style>
      :host {
        position: absolute;
        top: 100px;
        left: 100px;
        animation: tiaodong .8s linear infinite;
      }
      .left {
        position: absolute;
        width: 80px;
        height: 120px;
        background-color: red;
        border-radius: 50px 50px 0 0;
        transform: rotate(-45deg);
      }
      .right {
        width: 80px;
        position: absolute;
        height: 120px;
        background-color: red;
        border-radius: 50px 50px 0 0;
        left: 28px;
        transform: rotate(45deg)
      }
      @keyframes tiaodong {
        0% {
          transform: scale(1);
        }
        50% {
          transform: scale(1.05);
        }
        100% {
          transform: scale(1);
        }
      }
    </style>
    <div class="left"></div>
    <div class="right"></div>
  </template>
  <script>
    class MyHeart extends HTMLElement {
      constructor() {
        super();
        const templateElem = document.getElementById('my-heart');
        const content = templateElem.content.cloneNode(true);
        this.attachShadow({ mode: 'closed' }).appendChild(content);
      };
    }
    window.customElements.define('my-heart', MyHeart);
  </script>
</body>
</html>


360 度环绕太阳 ☀️


网络异常,图片无法展示
|


html:


<div class="sun"></div>


css:


body {
      display: flex;
      padding: 0;
      align-items: center;
      justify-content: center;
      min-height: 100vh;
      background-color: #f3eeea;
      margin: 0;
    }
    .sun {
      position: relative;
      left: 300px;
      width: 40vmin;
      height: 40vmin;
      border-radius: 100%;
      background-color: #fdf4ae;
    }
    .ray {
      position: absolute;
      top: 40vmin;
      left: 20vmin;
      width: 1vmin;
      height: 6.25vmin;
      transform-origin: 0 -20vmin;
      transform: translateY(25vmin);
      transition: all 1s linear;
    }
    .ray:after {
      content: '';
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      border-radius: 50%;
      background: linear-gradient(to bottom, #fcec71, #edc353);
    }
    .ray:after {
      height: 100%;
      transform-origin: 50% 100%;
    }


js:


// 动态生成360个光线
const sun = document.getElementsByClassName('sun')[0];
let html = '';
(new Array(360)).fill('hancao-design').forEach((item, index) => {
  html += `<div class="ray" style="transform: rotate(${index * 1}deg);"></div>`;
})
sun.innerHTML = html;


跃动的阳光 🌞


我感觉我录的 gif 一直都不好,我一定努力搞一个好用的 gif 录制软件


网络异常,图片无法展示
|


我就是单纯的用:


transition: all 1s linear;


配合定时器


setInterval(() => {
  analyser.getByteTimeDomainData(dataArray);
  dataArray.slice(0, 360).forEach((item, index) => {
    rays[index].style.height = `${item / 2}px`;
  })
}, 1000)


心的巧妙用法 ❤️


网络异常,图片无法展示
|


我做了一个类似于终端的界面,最后会出来一个心脏,我去点击之后就可以播放音乐并让太阳跃动起来~


// 内容如下,和那兔那篇文章关联起来了有没有~
hancao-design
for my feature lover
sun loading
...
retry
...
loaded
I wanna to be your sun
pleading enjoy the sunshine
click my-heart to start


window.customElements.define('my-heart', MyHeart);
    const list = ['<span style="color: red;"">hancao-design</span>', 'for my feature lover', 'sun loading', '...', 'retry',  '...', 'loaded', 'I wanna to be your sun', 'pleading enjoy the sunshine', 'click <span style="color: red;">my-heart</span> to start', '⬇️']
    const editor = document.getElementsByClassName('editor')[0];
    let i = 0;
    let len = list.length;
    const timer = setInterval(() => {
      if(i < len){
        editor.innerHTML += `<div>${list[i]}</div>`
      }else{
        clearInterval(timer);
        editor.innerHTML += `<my-heart></my-heart>`
      }
      i++;
    }, 500);


完整代码 🌲


<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>music</title>
  <style>
    body {
      display: flex;
      padding: 0;
      align-items: center;
      justify-content: center;
      min-height: 100vh;
      background-color: #f3eeea;
      margin: 0;
    }
    .sun {
      position: relative;
      left: 300px;
      width: 40vmin;
      height: 40vmin;
      border-radius: 100%;
      background-color: #fdf4ae;
    }
    .ray {
      position: absolute;
      top: 40vmin;
      left: 20vmin;
      width: 1vmin;
      height: 6.25vmin;
      transform-origin: 0 -20vmin;
      transform: translateY(25vmin);
      transition: all 1s linear;
    }
    .ray:after {
      content: '';
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      border-radius: 50%;
      background: linear-gradient(to bottom, #fcec71, #edc353);
    }
    .ray:after {
      height: 100%;
      transform-origin: 50% 100%;
    }
    .editor {
      width: 600px;
      height: 100vh;
      position: fixed;
      background-color: #1c1d21;
      left: 0px;
      color: #c1c5cd;
      padding-left: 32px;
      padding-top: 64px;
      font-size: 32px;
    }
  </style>
</head>
<body>
  <div class="sun"></div>
  <div class="editor"></div>
  <template id="my-heart">
    <style>
      :host {
        position: absolute;
        animation: tiaodong .8s linear infinite;
        cursor: pointer;
      }
      .left {
        position: absolute;
        width: 80px;
        height: 120px;
        background-color: red;
        border-radius: 50px 50px 0 0;
        transform: rotate(-45deg);
      }
      .right {
        width: 80px;
        position: absolute;
        height: 120px;
        background-color: red;
        border-radius: 50px 50px 0 0;
        left: 28px;
        transform: rotate(45deg)
      }
      @keyframes tiaodong {
        0% {
          transform: scale(1);
        }
        50% {
          transform: scale(1.05);
        }
        100% {
          transform: scale(1);
        }
      }
    </style>
    <div class="left"></div>
    <div class="right"></div>
  </template>
  <script>
    const sun = document.getElementsByClassName('sun')[0];
    let html = '';
    (new Array(360)).fill('hancao-design').forEach((item, index) => {
      html += `<div class="ray" style="transform: rotate(${index * 1}deg);"></div>`;
    })
    sun.innerHTML = html;
    const rays = sun.childNodes;
    class MyHeart extends HTMLElement {
      constructor() {
        super();
        const templateElem = document.getElementById('my-heart');
        const content = templateElem.content.cloneNode(true);
        this.onclick =() => {
            this.onclick = null;
            let audio = new Audio("dijia.mp3");
            let audioCtx = new (window.AudioContext || window.webkitAudioContext)();
            let source = audioCtx.createMediaElementSource(audio)
            let analyser = audioCtx.createAnalyser();
            source.connect(analyser);
            analyser.connect(audioCtx.destination)
            analyser.fftSize = 1024;
            let bufferLength = analyser.frequencyBinCount;
            let dataArray = new Uint8Array(bufferLength);
            audio.play();
            setInterval(() => {
              analyser.getByteTimeDomainData(dataArray);
              dataArray.slice(0, 360).forEach((item, index) => {
                rays[index].style.height = `${item / 2}px`;
              })
            }, 1000)
        }
        this.attachShadow({ mode: 'closed' }).appendChild(content);
      };
    }
    window.customElements.define('my-heart', MyHeart);
    const list = ['<span style="color: red;"">hancao-design</span>', 'for my feature lover', 'sun loading', '...', 'retry',  '...', 'loaded', 'I wanna to be your sun', 'pleading enjoy the sunshine', 'click <span style="color: red;">my-heart</span> to start', '⬇️']
    const editor = document.getElementsByClassName('editor')[0];
    let i = 0;
    let len = list.length;
    const timer = setInterval(() => {
      if(i < len){
        editor.innerHTML += `<div>${list[i]}</div>`
      }else{
        clearInterval(timer);
        editor.innerHTML += `<my-heart></my-heart>`
      }
      i++;
    }, 500);
  </script>
</body>
</html>


结束语


网络异常,图片无法展示
|


生活要有仪式感哦~

祝大家的生活充满阳光☀️


为什么题目中有奇迹再现呢,因为我引的音乐是这个童年经典的主题曲,本文标题也是在致敬最后一话的题目《致以辉煌的人》


我最后用《生命永存》这一话的经典台词结尾:


努力活完短暂的一生

将成果留给后代继承

人类就是如此反复

真的很了不起!


如果喜欢我的文章或者创意📖,可以用点赞+关注支持我~感谢✨


相关文章
|
负载均衡 网络协议 安全
负载均衡4层和7层区别
所谓四层就是基于IP+端口的负载均衡;七层就是基于URL等应用层信息的负载均衡
|
机器学习/深度学习 算法 网络架构
【CVPR2017】AOD-Net:端到端的除雾网络(原理&实操)
【CVPR2017】AOD-Net:端到端的除雾网络(原理&实操)
3570 0
【CVPR2017】AOD-Net:端到端的除雾网络(原理&实操)
allegro如何看元器件的高度
allegro如何看元器件的高度
1701 0
|
监控 关系型数据库 数据库
PostgreSQL 恢复模式错误日志增强 - 提供正在恢复的WAL(XLOG)文件位置
标签 PostgreSQL , the database system is starting up , the database system is in recovery mode 背景 当数据库异常停库,再次启动时。
3705 0
|
21天前
|
人工智能 开发者
千问AI平台 OPC 创新计划上线,百万 Token 补贴长期开放
为助推 OPC 生态、加速 AI 原生落地,千问AI平台推出长期补贴计划,一键报名即享至高200元先用后返普惠权益,提交申请可解锁至高 100 万元大额补贴,助力团队实现低成本模型调用。
194 1
|
12月前
|
消息中间件 缓存 算法
《数据之美》:队列的世界与算法实践
队列是先进先出的线性数据结构,常用于任务调度、消息传递等场景。本文详解其数组与链表实现、与栈的对比、核心算法(如BFS)、变种(双端队列、优先级队列)及实际应用,助你掌握选择与优化策略。
《数据之美》:队列的世界与算法实践
|
4月前
|
Linux 虚拟化 C++
VMware Tools 13.1 发布 - 虚拟机无缝交互必备组件
VMware Tools 13.1 发布 - 虚拟机无缝交互必备组件
285 0
|
10月前
|
存储 缓存 JSON
ESLint 全指南:从原理到实践,构建高质量的 JavaScript/TypeScript 代码
本文系统讲解ESLint的核心原理、配置详解与工程化实践,涵盖AST工作机制、TypeScript集成、Prettier协作、性能优化及CI/CD全流程集成,助你构建统一、健壮的前端代码质量体系。(238字)
632 1
|
Ubuntu 大数据 Linux
大数据入门系列 2:全网最全,VMware 虚拟机上安装 Ubuntu 完整步骤及需要注意的问题
大数据入门系列 2:全网最全,VMware 虚拟机上安装 Ubuntu 完整步骤及需要注意的问题
2724 1
大数据入门系列 2:全网最全,VMware 虚拟机上安装 Ubuntu 完整步骤及需要注意的问题
|
人工智能 数据安全/隐私保护 图形学
关于AI绘画优雅草央千澈整理的一份咒语(与AI对话提示词-应用于AI绘图和AI生成视频)-本文长期更新-本次更新2025年1月15日更新-长期更新建议点赞收藏
关于AI绘画优雅草央千澈整理的一份咒语(与AI对话提示词-应用于AI绘图和AI生成视频)-本文长期更新-本次更新2025年1月15日更新-长期更新建议点赞收藏
1365 4

热门文章

最新文章