vue一个页面实现音乐播放器的示例


Posted in Javascript onFebruary 06, 2018

本文介绍了vue一个页面实现音乐播放器的示例,分享给大家,具体如下:

效果如下:

vue一个页面实现音乐播放器的示例

vue一个页面实现音乐播放器的示例

项目地址:https://github.com/ermu592275254/MiniMusicPlayer

演示地址: https://ermu592275254.github.io/MiniMusicPlayer/(歌曲链接已失效)

开发前构思

界面

做音乐播放器,界面一定要炫酷。太low了听歌没感觉。本身是为了在上班的时候用,于是做成了一个类似网易云音乐的界面,大小合适。不用兼容手机端。

用css做图标

本怀着简单实用的需求去考虑,图标可用SVG、url或者css。相对于url,SVG和css更好一些。为了修炼,最终选择的css。利用好after和before,能减少很多dom嵌套。

.next {
  position: relative;
  display: inline-block;
  height: 36px;
  width: 36px;
  border: 2px solid #fff;
  border-radius: 20px;
  -webkit-border-radius: 20px;
  -moz-border-radius: 20px;
}
    
.next:before {
  content: '';
  height: 0;
  width: 0;
  display: block;
  border: 10px transparent solid;
  border-right-width: 0;
  border-left-color: #fff;
  position: absolute;
  top: 8px;
  left: 10px;
}

.next:after {
  content: '';
  height: 20px;
  width: 4px;
  display: block;
  background: #fff;
  position: absolute;
  top: 8px;
  left: 22px;
}

画一个唱片

网易云的唱片很好看,我也要弄一个唱片! 用好 box-shadow ,一个元素便可以做成很好看的唱片效果。

.disc {
  position: relative;
  margin-top: 10%;
  margin-left: 10%;
  width: 300px;
  height: 300px;
  border-radius: 300px;
  transform: rotate(45deg);
  background-image: radial-gradient(5em 30em ellipse, #fff, #000);
  border: 2px solid #131313;
  box-shadow: 0 0 0 10px #343935;
  opacity: 0.7;
}

用range做进度条

audio本身的样式很难看,并且不同的浏览器呈现出来的效果也不一样。当然你可以修改audio的样式,传统的做法是通过controls属性来隐藏audio,然后用div来代替。现在是html5时代了,当然要用更符合场景的新元素————range。

input[type=range] {
  -webkit-appearance: none;
  width: 80%;
  height: 8px;
  border-radius: 10px;
  background-color: #fff;
}
input[type=range]::-webkit-slider-thumb{
  -webkit-appearance: none;
} 
input[type=range]::-webkit-slider-runnable-track {
  height: 8px;
  border-radius: 20px;
}
input[type=range]:focus {
  outline: none;
}

input[type=range]::-webkit-slider-thumb {
  -webkit-appearance: none;
  margin-top: -3px;
  height: 14px;
  width: 14px;
  background: #eb7470;
  border-radius: 50%;
  border: solid 3px #fff;
  box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.5);
}

背景滤镜模糊

将图片设置为背景的感觉很棒,可以说整个播放器的颜值这背景提供了一半。设置也非常简单,用到了css3的滤镜。

.bg-blur {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 100%;
  height: 100%;
  background-position: center;
  background-repeat: no-repeat;
  background-size: cover;
  filter: blur(20px);
  z-index: -1;
}

背景图片通过js控制。

<div class="bg-blur" :style="`background-image:url(${currentSong.album_logo})`"></div>

歌曲资源

爬下接口

直接去虾米官网打开network,将url复制到postman里面去做请求。通过修改headers发现,会校验Referer。也就是说只有虾米允许的域名可以访问此接口。 http://api.xiami.com/web?v=2.0&app_key=1&key=aliez&page=1&limit=5&callback=jsonp154&r=search/songs

解决跨域问题

因为接口支持jsonp。起初尝试将chrome浏览器设置跨域,然后通过$.ajax去做一个jsonp的请求。可以正常访问。

之后突然不行了,是不是虾米做了限制?

遂改用node启动一个服务,去伪造referer发起请求,再将请求转发到页面。无意中写了一个代理。

...
case '/song':
  let songOptions = {
    url: 'http://api.xiami.com/web?'+ urlArr[1],
    headers: {
      'Referer': 'http://m.xiami.com/'
    }
  };
  function callback1(error, response, body) {
    if (!error && response.statusCode == 200) {
      res.end(body);
    }
  }
  request(songOptions, callback1);
  break;
...

歌词滚动

作为一款逼格比较高的播放器,歌词滚动是必须的。

原理

将每一句歌词保存为一个对象,有对应的时间。当歌曲播放的当前时长大于或等于歌词的时间,小于此歌词的下一句歌词的时间,那么就将此歌词滚动到可视区域。并且修改字体颜色。

格式化歌词

接口返回的歌词一脸懵逼,仔细研究一下,发现是有规律的。

[ti:aLIEz]
[ar:SawanoHiroyuki[nZk]:mizuki]
[al:o1]
[ly:?梢昂胫?
[mu:?梢昂胫?
[ma:]
[pu:]
[by:ttpod]
[total:268512]
[offset:0]
[00:00.000]<195>aLIEz <199>- <451>SawanoHiroyuki[nZk]:mizuki
[x-trans]彻头彻尾的谎言 - SawanoHiroyuki[nZk]:mizuki
[00:01.095]<201>作<250>?<200>:<201>??lt;200>野<199>弘<300>之
[x-trans]
[00:02.846]<200>作<150>曲<150>:<200>??lt;200>野<351>弘<349>之
[x-trans]
[00:20.828]<200>?Q<250>め<200>つ<201>け<149>ば<201>か<349>り
[x-trans]一直独断专权
[00:23.279]<200>自<200>惚<200>れ<200>を<200>着<400>た
[x-trans]总是自负逞强
[00:24.979]<200>チ<200>?<200>プ<450>な<550>hokori<350>で
[x-trans]明明只是一文不值的骄傲
......
  refactoringLyrics(lyric){
  let text = lyric.split('[offset:0]')[1];
  let textArr = text.split('\n');
  let lyricsArr = [], translate = [];
  textArr.forEach((item, index) => {
    let time = 0, text = '';
    if (item.indexOf('[x-trans]') > -1) {
      translate.push(item.split('[x-trans]')[1])
    } else if (item.trim() != '') {
      time = item.slice(1, 6).split(':');
      time = parseInt(time[0]) * 60 + parseInt(time[1]);
      text = item.slice(11);
      let arr = text.split('>');
      let str = arr.reduce((a, b) => {
        return a.split('<')[0] + b.split('<')[0]
      });
      let obj = {
        time: time,
        text: str
      };
      lyricsArr.push(obj);
    }
  });
  for (let i in translate) {
    lyricsArr[i].text = lyricsArr[i].text + '\n' + translate[i];
  }
  this.currentLyrics = lyricsArr;
},

搜索栏实现

同文件下子组件挂载

为了遵循模块化开发,决定将搜索栏写成一个子组件。在同一页面下写子组件,子组件挂载到对应的template就有讲究了。此template不能被父组件的挂载元素包含,否则父组件渲染时会因为无法渲染子组件中的数据而报undefined。

<div id="app" class="main">
...
</div>
<template id="search-box">
...
</template>

var searchBox = {
    template: '#search-box',
    props: {
      isShow: Boolean,
      openFun: Function
    },
    data(){
      return {
        resultList: [],
        searchValue: '',
      }
    },
    methods: {
    }
  };
 new Vue({
  el: '#app',
  components: {
    'com-tip': tip,
    'search-box': searchBox
  },
  ...
})

eventBus解决数据传输

通过jsonp去请求数据,需要设置一个callback函数,此callback写成一个全局函数,如果不这样写,而是通过 searchBox.methods.callback的形式,this指向将为methods。而无法直接给searchBox的data赋值。 于是通过eventBus来处理,这样更易维护。

var EventBus = new Vue();
var callBack = function(result) {
  console.log(result);
  EventBus.$emit('callBack', result);
};
...
mounted(){
  let self = this;
  EventBus.$on('callBack', function(res) {
    if (res && res.data) {
      self.resultList = res.data.songs;
    }
  })
}
...

localStrong储存歌曲信息

下次再打开,应该播放列表应该保留上一次的数据,这个可直接用localstrong实现

踩了坑

prop传递数据

使用cdn,vue的prop只支持中线格式,驼峰格式不生效

ps: 在用webpack打包的项目中用驼峰是可以,在打包过程中,会做处理。

// 正确写法
<search-box :is-show="showSearch" :open-fun="openSearch" @push-song="pushNewSong"
        @play-song="playSong"></search-box>
// 错误写法
<search-box :isShow="showSearch" :openFun="openSearch" @pushSong="pushNewSong"
        @playSong="playSong"></search-box>

待优化

手动修改进度,偶尔会不生效。

搜索暂不支持分页

不支持建歌单

背景颜色与进度条颜色相近需修改进度条颜色

不支持播放模式选择-单曲循环-随机播放

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
javascript attachEvent绑定多个事件执行顺序问题
Oct 20 Javascript
小试JQuery的AutoComplete插件
May 04 Javascript
js 实现在离开页面时提醒未保存的信息(减少用户重复操作)
Jan 16 Javascript
Jquery 的outerHeight方法使用介绍
Sep 11 Javascript
jQuery操作input值的各种方法总结
Nov 21 Javascript
jQuery Masonry瀑布流插件使用详解
Nov 17 Javascript
angular和BootStrap3实现购物车功能
Jan 25 Javascript
js中DOM三级列表(代码分享)
Mar 20 Javascript
vue项目中在外部js文件中直接调用vue实例的方法比如说this
Apr 28 Javascript
使用layui的layer组件做弹出层的例子
Sep 27 Javascript
PHP 502bad gateway原因及解决方案
Nov 13 Javascript
js前端图片加载异常兜底方案
Jun 21 Javascript
使用百度地图实现地图网格的示例
Feb 06 #Javascript
js中的闭包学习心得
Feb 06 #Javascript
JS基于设计模式中的单例模式(Singleton)实现封装对数据增删改查功能
Feb 06 #Javascript
Vue仿今日头条实例详解
Feb 06 #Javascript
electron demo项目npm install安装失败的解决方法
Feb 06 #Javascript
详解React开发必不可少的eslint配置
Feb 05 #Javascript
详解js的作用域、预解析机制
Feb 05 #Javascript
You might like
PHP 多维数组排序实现代码
2009/08/05 PHP
PHP 创建标签云函数代码
2010/05/26 PHP
PDO::query讲解
2019/01/29 PHP
javascript 中对象的继承〔转贴〕
2007/01/22 Javascript
javascript 类方法定义还是有点区别
2009/04/15 Javascript
兼容FF和IE的动态table示例自写
2013/10/21 Javascript
js单例模式详解实例
2013/11/21 Javascript
带左右箭头图片轮播的JS代码
2013/12/18 Javascript
js字符串完全替换函数分享
2014/12/03 Javascript
解决js图片加载时出现404的问题
2020/11/30 Javascript
Bootstrap组件学习之导航、标签、面包屑导航(精品)
2016/05/17 Javascript
javascript中的 object 和 function小结
2016/08/14 Javascript
js select实现省市区联动选择
2020/04/17 Javascript
微信小程序 天气预报开发实例代码源码
2017/01/20 Javascript
基于javaScript的this指向总结
2017/07/22 Javascript
vue cli安装使用less的教程详解
2019/07/12 Javascript
详解ES6新增字符串扩张方法includes()、startsWith()、endsWith()
2020/05/12 Javascript
js在HTML的三种引用方式详解
2020/08/29 Javascript
[01:05:12]2014 DOTA2国际邀请赛中国区预选赛 TongFu VS CIS-GAME
2014/05/21 DOTA
python实现sublime3的less编译插件示例
2014/04/27 Python
让python同时兼容python2和python3的8个技巧分享
2014/07/11 Python
python海龟绘图实例教程
2014/07/24 Python
python中的常量和变量代码详解
2018/07/25 Python
python模块常用用法实例详解
2019/10/17 Python
python爬虫模块URL管理器模块用法解析
2020/02/03 Python
Python读取xlsx数据生成图标代码实例
2020/08/12 Python
Python timeit模块原理及使用方法
2020/10/10 Python
Python使用paramiko连接远程服务器执行Shell命令的实现
2021/03/04 Python
IE滤镜与CSS3效果(详细整理分享)
2013/01/25 HTML / CSS
CSS实现半透明边框与多重边框的场景分析
2019/11/13 HTML / CSS
应用服务器有那些
2012/01/19 面试题
演讲稿格式
2014/04/30 职场文书
我爱读书演讲稿
2014/05/07 职场文书
2014入党积极分子批评与自我批评思想汇报
2014/09/20 职场文书
分享Python获取本机IP地址的几种方法
2022/03/17 Python
Python必备技巧之函数的使用详解
2022/04/04 Python