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 相关文章推荐
jQuery 插件 将this下的div轮番显示
Apr 09 Javascript
kmock javascript 单元测试代码
Feb 06 Javascript
Jquery提交表单 Form.js官方插件介绍
Mar 01 Javascript
js中的屏蔽的使用示例
Jul 30 Javascript
简单的js表单验证函数
Oct 28 Javascript
JS正则表达式大全(整理详细且实用)
Nov 14 Javascript
js实现类似新浪微博首页内容渐显效果的方法
Apr 10 Javascript
JavaScript实现拖拽网页内元素的方法
Apr 15 Javascript
学习JavaScript设计模式之装饰者模式
Jan 19 Javascript
AngularJS 应用身份认证的技巧总结
Nov 07 Javascript
使用yeoman构建angular应用的方法
Aug 14 Javascript
使用vue打包时vendor文件过大或者是app.js文件很大的问题
Jun 29 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闭包(Closure)使用详解
2013/05/02 PHP
解析php开发中的中文编码问题
2013/08/08 PHP
php类的定义与继承用法实例
2015/07/07 PHP
CI框架网页缓存简单用法分析
2018/12/26 PHP
PHP 多进程与信号中断实现多任务常驻内存管理实例方法
2019/10/04 PHP
javascript解三阶幻方(九宫格)
2015/04/22 Javascript
jquery实现用户打分评分特效
2015/05/28 Javascript
Bootstrap~多级导航(级联导航)的实现效果【附代码】
2016/03/08 Javascript
利用jquery去掉时光轴头尾部线条的方法实例
2017/06/16 jQuery
vue 兄弟组件的信息传递的方法实例详解
2019/08/30 Javascript
Vue-cli3项目引入Typescript的实现方法
2019/10/18 Javascript
mapboxgl实现带箭头轨迹线的代码
2021/01/04 Javascript
原生JavaScript实现购物车
2021/01/10 Javascript
全面解析js中的原型,原型对象,原型链
2021/01/25 Javascript
[02:49]DAC2018决赛日TOP5 LGD开启黑暗之门绝杀VP
2018/04/08 DOTA
解决python2.7 查询mysql时出现中文乱码
2016/10/09 Python
Python用61行代码实现图片像素化的示例代码
2018/12/10 Python
PyCharm 设置SciView工具窗口的方法
2019/01/15 Python
Python 调用 Windows API COM 新法
2019/08/22 Python
python线程中的同步问题及解决方法
2019/08/29 Python
基于python的selenium两种文件上传操作实现详解
2019/09/19 Python
解析Python3中的Import
2019/10/13 Python
Python基于内置函数type创建新类型
2020/10/22 Python
CSS3 Calc实现滚动条出现页面不跳动问题
2017/09/14 HTML / CSS
详解CSS3+JS完美实现放大镜模式
2020/12/03 HTML / CSS
GANT英国官方网上商店:甘特衬衫
2018/02/06 全球购物
屈臣氏乌克兰:Watsons UA
2019/10/29 全球购物
远东集团网络工程师面试题
2014/10/20 面试题
应届生船舶驾驶求职信
2013/10/19 职场文书
自主招生自荐信范文
2013/12/04 职场文书
优秀学生自我鉴定范例
2013/12/18 职场文书
《神奇的克隆》教学反思
2014/04/10 职场文书
2014中学教师节广播稿
2014/09/10 职场文书
诉讼授权委托书
2014/10/15 职场文书
2014预防青少年违法犯罪工作总结
2014/12/10 职场文书
2015年质量月活动总结报告
2015/03/27 职场文书