原生JS实现音乐播放器

前言

虽然现在有很多现成的库去实现音乐播放器功能,但是总感觉只会使用人家的第三方库缺点啥,于是就想着自己使用原生JS写一个,也不是特别难。

完整代码

html

DOCTYPE html>
<html lang="en">

  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Documenttitle>
    <link rel="shortcut icon" href="./assets/favicon.ico" type="image/x-icon">
    <link rel="stylesheet" href="./css/index.css">
  head>

  <body>
    <audio controls src="./assets/春娇与志明.mp3">audio>
    <div class="container">
      <ul class="lrc-list">
      ul>
      <script src="./js/data.js">script>
      <script src="./js/index.js">script>
    div>
  body>

html>

css

* {
  margin: 0;
  padding: 0;
}

body {
  background-color: #000;
  color: #666;
  /* 对行盒元素进行居中 */
  text-align: center;
}

audio {
  width: 450px;
  margin: 30px 0;
}

.container {
  height: 420px;
  overflow: hidden;
  /* border: 2px solid #fff; */
}

.container ul {
  /* border: 2px solid #fff; */
  /* 只针对数值类的有效 */
  transition: 0.3s;
  list-style: none;
}

.container li {
  height: 30px;
  line-height: 30px;
  /* 过渡在进去还有离开时都要有 */
  transition: 0.3s;
}

.active {
  color: #fff;
  transform: scale(1.2);
}

js

滚动歌词的效果的实现其实就是监听audio标签,时间改变的同时会显示对应的歌词

var lrc = `[00:00.527]Jcool:
[00:23.027]有个女仔令我思想变得大个
[00:25.495]当初
[00:26.120]我幼稚行为对你犯下大错
[00:28.617]你话我唔识谂 用钱买无用饰品
[00:31.381]你慢慢心淡觉得我对感情唔认真
[00:34.260]要知道男人系天生嘅小朋友
[00:37.176]小朋友弱点会忽略另一半感受
[00:39.799]要改正好简单我只系欠调教
[00:42.503]经历得多反而可以令到爱意浓厚
[00:44.723]Vai:
[00:45.255]志明嘅世界永远好动带着可爱
[00:47.944]佢冇时间迷茫 爱情错过却唔可再
[00:50.696]从开始走到结尾哪个不会变大个
[00:53.505]但春娇想要那个你又有谁可以劝阻
[00:56.241]等待 UFO 纵有变数
[00:58.999]最普通嘅佢哋世上遍布
[01:01.803]爱漫春天散落每个季节嘅消耗
[01:04.706]看着花瓣跌落过程撑得过衰老
[01:07.205]欧阳:
[01:09.059]重新出发吗 huh 更渴望未来
[01:13.869]以往这少年懂爱吗
[01:17.438]仿佛不够
[01:20.203]成长会进化吗 也信念自由
[01:25.058]我爱这少年讽刺吗
[01:28.625]这花开吗
[01:30.327]留:
[01:30.972]我爱你 你是唱将我做配合
[01:33.418]但你予我这过程细致给我培训
[01:36.390]情与爱 太过复杂 我要太多喘息
[01:39.072]但你爱我嘅以后不会太过忐忑
[01:41.945]当拥有嘅时候 又接近放手
[01:44.718]循环播放剧情有多少个然后
[01:47.085]如果系现实我会选择打破现实
[01:49.633]喺你嘅世界里面我会选择慢慢渐入
[01:52.312]Vai:
[01:52.972]志明嘅世界永远好动带着可爱
[01:55.656]佢冇时间迷茫 爱情错过却唔可再
[01:58.497]从开始走到结尾哪个不会变大个
[02:01.286]但春娇想要那个你又有谁可以劝阻
[02:04.039]等待 UFO 纵有变数
[02:06.725]最普通嘅佢哋世上遍布
[02:09.529]爱漫春天散落每个季节嘅消耗
[02:12.452]看着花瓣跌落过程撑得过衰老
[02:15.606]欧阳:
[02:16.709]重新出发吗 huh 更渴望未来
[02:21.541]以往这少年懂爱吗
[02:25.092]仿佛不够
[02:27.965]成长会进化吗 也信念自由
[02:32.853]我爱这少年讽刺吗
[02:36.415]这花开吗
[02:37.912]Garyu:
[02:37.981]破碎婚姻里出身逼出佢嘅硬净
[02:40.640]佢再牺牲佢嘅率真改变佢嘅硬颈
[02:43.493]戴眼镜嘅佢明白波珠解决唔到逃避
[02:46.318]要长大要负责任缩短两个人嘅距离
[02:48.998]美梦里学会感嘅
[02:51.559]你亦放肆你的爱
[02:54.109]用力转载 越过比赛
[02:56.845]为我掩盖 都因为爱
[03:00.770]欧阳:
[03:01.883]重新出发吗 huh 更渴望未来
[03:06.757]以往这少年懂爱吗
[03:10.215]仿佛不够
[03:13.077]成长会进化吗 也信念自由
[03:18.048]我爱这少年讽刺吗
[03:21.629]这花开吗`;

实现具体内容

/* 
解析歌词字符串,得到一个歌词对象的数组
每个歌词对象:
{time:开始时间,words:歌词内容}
*/
function parseLrc() {
  const lines = lrc.split("\n");
  const result = [];
  for (let i = 0; i < lines.length; i++) {
    const str = lines[i];
    const parts = str.split("]");
    const timeStr = parts[0].substring(1);
    const obj = {
      time: parseTime(timeStr),
      words: parts[1] || "",
    };
    result.push(obj);
  }
  return result;
}

function parseTime(timeStr) {
  const parts = timeStr.split(":");
  // +转换为数字
  return +parts[0] * 60 + +parts[1];
}

const lrcData = parseLrc();
// console.log(lrcData);

// 获取需要的dom
var doms = {
  audio: document.querySelector("audio"),
  ul: document.querySelector(".lrc-list"),
  container: document.querySelector(".container"),
};

/* 
计算出当前情况下,lrcData数组中应该高亮显示的歌词下标
找到的是第一个大于当前时间的上一句
*/
function findIndex() {
  const curTime = doms.audio.currentTime; //播放器当前时间
  for (let i = 0; i < lrcData.length; i++) {
    if (curTime < lrcData[i].time) {
      return i - 1;
    }
  }
  // 播放到最后一句了
  return lrcData.length - 1;
}

// 创建歌词元素
function createLrcEle() {
  // 创建文档片段
  const frag = document.createDocumentFragment();
  for (let i = 0; i < lrcData.length; i++) {
    const li = document.createElement("li");
    li.textContent = lrcData[i].words;
    frag.appendChild(li);
  }
  doms.ul.appendChild(frag);
}

createLrcEle();

// 容器高度
const containerHeight = doms.container.clientHeight;
// 每个li的高度
const liHeight = doms.ul.children[0].clientHeight;
// 最大偏移量
const maxOffset = doms.ul.clientHeight - containerHeight;

/* 
设置ul元素的偏移量
*/
function setOffset() {
  const index = findIndex();
  let offset = liHeight * index + liHeight / 2 - containerHeight / 2;
  if (offset < 0) {
    offset = 0;
  }
  if (offset > maxOffset) {
    offset = maxOffset;
  }
  doms.ul.style.transform = `translateY(-${offset}px)`;
  // 去除之前样式
  const oriStyLi = doms.ul.querySelector(".active");
  if (oriStyLi) {
    oriStyLi.classList.remove("active");
  }
  //   console.log(index);
  const li = doms.ul.children[index];
  if (li) {
    doms.ul.children[index].classList.add("active");
  }
}

doms.audio.addEventListener("timeupdate", setOffset);

你可能感兴趣的:(javascript,开发语言,ecmascript)