首页 > 建站教程 > CSS3+HTML5 >  带歌词同步,带上一曲下一曲的自定义界面的html5播放器正文

带歌词同步,带上一曲下一曲的自定义界面的html5播放器

    前段时间,我爱模板网做项目涉及到一个音乐播放器,自定义的界面,要能歌词同步,没办法,只能自己写了。这个播放器带歌词同步,并且支持上一曲下一曲,进度条可以拖拽,拖拽时,歌词也会同步变化。歌词是通过ajax根据地址获取的,格式随便,只要按照“[时间]歌词”的格式来即可。
    首先看下效果:html5带歌词同步的音乐播放器
    下面是播放器js代码:
//获取歌曲链接并插入dom中
var myAudio = null;
var control = null;
var prevSongBtn = null;
var nextSongBtn = null;
var loadingBar = null;
var playList = ['http://www.5imoban.net/view/demomusic/niliuchenghe.mp3','http://www.5imoban.net/view/demomusic/xiaopingguo.mp3'];
var lrcList = ['http://www.5imoban.net/view/demomusic/niliuchenghe.txt','http://www.5imoban.net/view/demomusic/xiaopingguo.txt'];
var nowIdx = 0;
var drag = null;
var speed = null;
var lrcArr = []; //保存歌词
var timestamp = []; //保存时间戳
var lrcArea = '';
var timer1 = null;
var timer2 = null;
var timer3 = null;

initPlayer();

function initPlayer(){
	loadingBar = document.querySelector('#loading');
	myAudio = document.getElementById("audio");
	control = document.querySelector('#control');
    drag = document.getElementById("drag");
    speed = document.getElementById("speed");
    lrcArea = document.getElementById('lrc');
	prevSongBtn = document.querySelector('#prevSong');
	nextSongBtn = document.querySelector('#nextSong');
	prevSongBtn.addEventListener('touchend',prevEv, false);
	nextSongBtn.addEventListener('touchend',nextEv, false);

	playSong(0);

}

//获取歌曲链接并插入dom中
function playSong(idx){
    clearInterval(timer1);
    clearInterval(timer2);
    clearInterval(timer3);
	loadingBar.style.display = 'block';
    myAudio.src = playList[idx];
    //myAudio.loop = true;
    playCotrol(); //播放控制函数

	//歌词
	lrcArr = [];
	timestamp = [];
	lrcArea.innerHTML = '';
	handleLrc(idx);
}

//点击播放/暂停
function clicks() {
    control.removeEventListener('click',controlEv, false);
    control.addEventListener('click',controlEv, false);
}

function controlEv(){
    if (control.classList.contains("play")) {
        control.classList.add("pause");
        control.classList.remove("play");
        myAudio.play();//开始播放
        dragMove();//并且滚动条开始滑动
    } else {
        control.classList.remove("pause");
        control.classList.add("play");
        myAudio.pause();
    }
}

//播放时间
function timeChange(time, timePlace) {//默认获取的时间是时间戳改成我们常见的时间格式
    var timePlace = document.getElementById(timePlace);
    //分钟
    var minute = time / 60;
    var minutes = parseInt(minute);
    if (minutes < 10) {
        minutes = "0" + minutes;
    }
    //秒
    var second = time % 60;
    seconds = parseInt(second);
    if (seconds < 10) {
        seconds = "0" + seconds;
    }
    var allTime = "" + minutes + "" + ":" + "" + seconds + ""
    timePlace.innerHTML = allTime;
}

//播放事件监听
function playCotrol() {
	//歌曲一经完整的加载完毕
    myAudio.addEventListener("loadeddata",loadeddataEv, false);
    //暂停
    myAudio.addEventListener("pause",pauseEv, false);
    //播放
    myAudio.addEventListener("play",playEv, false);
    myAudio.addEventListener("ended",endEv, false);
}

//加载完成播放事件
function loadeddataEv(){
	loadingBar.style.display = 'none';
    control.classList.add("play");
    control.classList.remove("pause");
    addListenTouch(); //歌曲加载之后才可以拖动进度条
    var allTime = myAudio.duration;
    timeChange(allTime,'endTime');
	setStartTime();
    clicks();
    lrcSync();
}

//时间跳动
function setStartTime(){
	clearInterval(timer1);
	timer1 = setInterval(function() {
        var currentTime = myAudio.currentTime;
        timeChange(currentTime, "startTime");
    }, 1000);
}

function pauseEv() { //监听暂停
    control.classList.add("play");
    control.classList.remove("pause");
    if (myAudio.currentTime == myAudio.duration) {
        myAudio.pause();
        myAudio.currentTime = 0;
    }
    clearInterval(timer1);
    clearInterval(timer2);
    clearInterval(timer3);
}

function playEv(){
    control.classList.add("pause");
    control.classList.remove("play");
    dragMove();
	setStartTime();
	lrcSync();
}

function endEv(){
    nextEv();
}

//进度条
 var startX, x, aboveX = 0;

//拖动监听touch事件
function addListenTouch() {
    drag.addEventListener("touchstart", touchStart, false);
    drag.addEventListener("touchmove", touchMove, false);
    drag.addEventListener("touchend", touchEnd, false);
}

//touchstart,touchmove,touchend事件函数
function touchStart(e) {
     var touch = e.touches[0];
     startX = touch.pageX; 
 }
function touchMove(e) {
     var touch = e.touches[0];
     x = touch.pageX - startX; //滑动的距离
     drag.style.left = aboveX + x + "px"; //  
     speed.style.left = -((window.innerWidth) - (aboveX + x)) + "px";
 }
function touchEnd(e) { //手指离开屏幕
     e.preventDefault();
     aboveX = parseInt(drag.style.left);
     var touch = e.touches[0];
     var dragPaddingLeft = drag.style.left;
     var change = dragPaddingLeft.replace("px", "");
     numDragpaddingLeft = parseInt(change);
     var currentTime = (numDragpaddingLeft / (window.innerWidth - 30)) * myAudio.duration;//30是拖动圆圈的长度,减掉是为了让歌曲结束的时候不会跑到window以外
     myAudio.currentTime = currentTime;
 }

//拖动的滑动条前进
function dragMove() {
	clearInterval(timer3);
    timer3 = setInterval(function() {
        drag.style.left = (myAudio.currentTime / myAudio.duration) * (window.innerWidth - 30 - 30) + "px";
        speed.style.left = -((window.innerWidth-30) - (myAudio.currentTime / myAudio.duration) * (window.innerWidth - 30 - 30)) + "px";
    }, 500);
}

//上一首
function prevEv(){
	nowIdx--;
	if(nowIdx < 0){
		nowIdx=0;
	}
	playSong(nowIdx);
}

//下一首
function nextEv(){
	nowIdx++;
	if(nowIdx > (playList.length-1)){
		nowIdx=playList.length-1;
	}
	playSong(nowIdx);
}

//处理lrc
function handleLrc(idx){
    var xhr = new XMLHttpRequest();
    xhr.open('GET',lrcList[idx], false);
    xhr.send(null);
    if (xhr.readyState == 4 && xhr.status == 200) {
        var lrc = xhr.responseText;
        var re = /(\[.+\])(.+)?/gm, tmpArr, i, len;
        var txt = lrc.replace(re,function(a, b, c) {
            return b + (c === undefined ? '&nbsp;': c) + '\n';
        });
        tmpArr = txt.split('\n');
        //去除空白歌词
		for (i = 0, len = tmpArr.length; i < len; i++) {
	    	var item = trim(tmpArr[i]);
			if (item.length > 0) {
				lrcArr.push(item);
			}
		}
		var _html = '';
		for (i = 0; i < lrcArr.length; i++) {
			if (i === 0) {
				_html += '<li class="on">';
			}else if(i === 1 || i === 2){
				_html += '<li>';
			}else{
				_html += '<li class="hidden">';
			}
			_html += lrcArr[i].replace(/\[.+\]/i, '');
			_html += '</li>';
			//处理时间
			timestamp.push(lrcArr[i].replace(re,function(a, b, c) {
				return b;
			}).replace('[', '').replace(']', ''));
		}
		lrcArea.innerHTML = _html;
    }
}

//歌词同步
function lrcSync(){
    clearInterval(timer2);
    timer2 = setInterval(function() {
		var curTime = myAudio.currentTime;
		for (var i = 0, len = timestamp.length - 1; i < len; i++) {
			var prevTime = formatTimeStamp(timestamp[i]),
			nextTime = formatTimeStamp(timestamp[i + 1]);
			//当前播放时间与前后歌词时间比较,如果位于这两者之间则转到该歌词
			if (parseFloat(curTime) > prevTime && parseFloat(curTime) < nextTime) {
				var allLines = document.querySelectorAll('#lrc li');
				for(var j=0; j<allLines.length; j++){
					allLines[j].classList.add('hidden');
					allLines[j].classList.remove('on');
				}
				try{
					allLines[i+1].classList.add('on');
					allLines[i+1].classList.remove('hidden');
					allLines[i].classList.remove('hidden');
					allLines[i+2].classList.remove('hidden');

				}catch(e){}
				break;
			}
		}
	},300);
}

function trim(str) {
	return str.replace(/(^\s*)|(\s*$)/g, "");
}

function formatTimeStamp(timestamp) {
	var re = /([0-9]+):([0-9]+)\.([0-9]+)/i,
	seconds = timestamp.replace(re, function(a, b, c, d) {
		return Number(b * 60) + Number(c) + parseFloat('0.' + d);
	});
	 return seconds;
}