网页版音频播放器,歌词随音乐而动

制作不易,多多支持,谢谢!!

我的博客里面还有关于视频播放器的,感兴趣的小伙伴可以来看看。

这个是效果图 

 这是利用audio做的一个歌词随音乐而动的html页面。


这个简单的音频播放器是用ajax请求本地服务器的lrc文件,lrc文件就是歌词文件。

歌词滚动的基本思想

把歌词放在盒子里面,通过audio的timeupdata事件监听音乐的播放,并获取当前播放的时间currentTime,然后通过当前播放的时间于歌词的时间匹配,匹配到的话就把歌词盒子往上移动。

第一步:通过ajax获取本地歌词

//用ajax请求数据
	function createXHR(){
		if(typeof(XMLHttpRequest)!='undefined'){
			return new XMLHttpRequest;
		}else if(typeof(ActiveXObject)!='undefined'){
			var xhrArr=['Microsoft.XMLHTTP','MSXML2.XMLHTTP.6.0','MSXML2.XMLHTTP.5.0','MSXML2.XMLHTTP.4.0','MSXML2.XMLHTTP.3.0','MSXML2.XMLHTTP.2.0'];
			var len=xhrArr.length,xhr;
			for(var i=0;i<length;i++){
				try{
					xhr=new ActiveXObject(xhrArr[i]);
					break;
				}catch(ex){
					
				}
				return xhr;
			}
		}else{
			throw new Error('no XHR')
		}
	}
	//创建XMLHttpRequest对象
	var xhr=createXHR(),data=null;
	//创建HTTP请求
	xhr.open('get','mz.lrc');
	//发送请求
	xhr.send(null);
	//响应XMLHttpRequest对象状态变化的函数,onreadystatechange在readystatechange属性发生改变时触发
	xhr.onreadystatechange=function(){
		//异步调用成功,相应内容解析完成,可在客户端调用
		if(xhr.readyState===4){
			if((xhr.status>=200&&xhr.status<300)||xhr.status==304){//304表示请求资源没有被修改,可以使用缓存
				//获得服务器返回数据
				data=xhr.responseText;
				//渲染数据到页面中
				renderDataToDom(data);
			}
		}
	}

 

第二部:处理歌词

歌词的格式是这样的

我们要转换的格式 

这里第108秒跑到了前面,所以我把时间排好序,又放到了一个数组中,用这个数组来滚动音乐。

 

 

function renderDataToDom(data){
		//将歌词中的时间格式转换成多少秒
		var pattern=/\[(\d{2}):(\d{2})\.(\d{2})\](.*)/g;
		var result=pattern.exec(data);
		while(result!=null){
			var time=parseInt(result[1])*60+parseInt(result[2])+parseFloat('0.'+result[3]);
			if(result[4]){
				lrcObj[time]=result[4];
			}
			result=pattern.exec(data);
		}
		//转换后的格式,有的顺序可能不对,转换顺序按从小到大
		var i=0;
		var fragment=document.createDocumentFragment();
		var li=null,sortObj={};
		for(var key in lrcObj){
			keysArr[i]=parseFloat(key);
			i++;
		}
		keysArr.sort((a,b)=>a-b);
		for(var i=0;i<keysArr.length;i++){
			sortObj[keysArr[i]]=lrcObj[keysArr[i]];
/*			console.log(''+keysArr[i]+lrcObj[keysArr[i]]);*/
			li=document.createElement("li");
			li.appendChild(document.createTextNode(sortObj[keysArr[i]]));
			fragment.appendChild(li);
		}
		//sortObj虽然是排完序后的对象,但顺序还是和之前一样,所以在排序的时候就把li加载好,匹配歌词的时候用时间来就行了。
		//将歌词添加到lyricsBox中
		lyricsBox.appendChild(fragment);
		//var len=Object.keys(lrcObj).length;//获取这个对象的长度
	}

第三步、创建audio对象,实现歌词随音乐而动

//创建audio对象
	var audio=new Audio;
	var isPlay=false;
	var nowTime;
	audio.src='芒种.mp3';
	audio.loop=true;
	audioPlay();
	function audioPlay(){
		//播放、暂停
		var play=document.getElementsByClassName('play')[0];
		console.log(keysArr);
		play.onclick=function(){
			if(isPlay){
				this.style.backgroundImage='url("img/pause.png")';
				isPlay=false;
				audio.pause();
			}else{
				this.style.backgroundImage='url("img/play.png")';
				isPlay=true;
				audio.play();
			}
			
		}
	}
	//歌词虽页面而动
	var m=0;//第几句,贯穿全剧
	var preTime=0;
	audio.ontimeupdate=function(){
		nowTime=this.currentTime;
		nowTime=parseFloat(nowTime.toFixed(2));	
		console.log(nowTime);
		console.log(preTime);
		//检测是否一首歌播放完
		if(nowTime<preTime){
			document.getElementsByClassName('lyricsBox')[0].children[0].children[0].children[m-1].style.color='#fff';
			document.getElementsByClassName('lyricsBox')[0].children[0].children[0].children[m-1].style.fontSize='18px';
			console.log(1111);
			m=0;
			preTime=0;
		}else{
			preTime=nowTime;
		}
		if(nowTime>=(keysArr[m]-0.25)){
			console.log(typeof(keysArr[m]))
			if(m>=1){
				document.getElementsByClassName('lyricsBox')[0].children[0].children[0].children[m].previousElementSibling.style.color='#fff';
				document.getElementsByClassName('lyricsBox')[0].children[0].children[0].children[m].previousElementSibling.style.fontSize='18px';
			}
			document.getElementsByClassName('lyricsBox')[0].children[0].children[0].children[m].style.color='red';
			document.getElementsByClassName('lyricsBox')[0].children[0].children[0].children[m].style.fontSize='22px';
			m++;
			document.getElementsByClassName('lyricsBox')[0].children[0].style.top=-33*(m-4)+'px';	
		}
		
	}

    这里让当前的时间和之前做的时间数组匹配用了一个方法,先声明一个全局变量,并赋值为0,作为记录播放到第几局的一个变量,同时也是时间数组的下标,因为时间数组里面,下边就是第几句,对应的值就是第几句播放时的时间,当现在的时间大于时间数组的时间的时候,让该句歌词颜色变红并且字体变大,然后m++,然后让歌词盒子向上移动一个li的高度。这里歌词盒子有个初始top,这样做为了让当前的歌词显示在屏幕的中间。

   当前歌词变完色的同时,上一句歌词还要变回原样,所以在上面那一步操作之前,还要把当前m对应的歌词样式变回原样,还要注意的是这个m要大于一。

遇到的问题及解决

解决循环(loop)为true的时候,onended这个事件是不能用的问题

   还有就是,当循环(loop)为true的时候,onended这个事件是不能用的,所以我加了一个if语句,来判断这首歌是否播放完。做法就是,声明一个pretime的变量,赋初值为0,意思就是当前timeupdata时间监听的currentTime的上一个currentTime,比较preTime和currentTime,正常情况下currentTime是肯定大于preTime的,但当第一次播放结束时currentTime是小于preTime的,所以就用这个来判断音乐的循环播放。

如果在子盒子上加个margin-top,这个属性会作用到父盒子上,解决方法就是给子盒子加个边框

获取音频的currentTime属性,其实得到的是一个字符串,在比较的时候不知道这个问题,每次在判断是否播放完的时候的第十秒就出错了,然后把它转换成数字就行了。

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值