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

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

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

这个是效果图 

 这是利用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=200&&xhr.status<300)||xhr.status==304){//304表示请求资源没有被修改,可以使用缓存
				//获得服务器返回数据
				data=xhr.responseText;
				//渲染数据到页面中
				renderDataToDom(data);
			}
		}
	}

 

第二部:处理歌词

歌词的格式是这样的

网页版音频播放器,歌词随音乐而动_第1张图片

我们要转换的格式 

这里第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

第三步、创建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=(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属性,其实得到的是一个字符串,在比较的时候不知道这个问题,每次在判断是否播放完的时候的第十秒就出错了,然后把它转换成数字就行了。

你可能感兴趣的:(寒假前端)