1. 程式人生 > >audio-基於Vue的一個小專案(上傳音樂連結)

audio-基於Vue的一個小專案(上傳音樂連結)

1 標籤定義聲音,比如音樂或其他音訊流。
2 設定為自動播放的 audio 元素:autoplay=“autoplay”
但是隻有pc端可以實現 移動端不行(pc端的瀏覽器要比移動端的完善很多,對有些屬性支援也會好很多)

3 audio不單單是個標籤 他也是window下的一個物件,物件就有屬性和方法,作為物件他有哪些常用的方法呢

物件屬性:
currentTime 獲取當前播放時間
duration 獲取歌曲的總時間
play 是否在播放 返回true/false
pause 是否暫停 返回true/false
物件方法:
play() 播放歌曲
pause() 暫停歌曲
load()重新載入歌曲

4 onloadedmetadata 事件在指定視訊/音訊(audio/video)的元資料載入後觸發。
視訊/音訊(audio/video)的元資料包含: 時長,尺寸大小(視訊),文字軌道。
視訊/音訊(audio/video)在載入過程中,觸發的順序如下:

onloadstart
ondurationchange
onloadedmetadata
onloadeddata
onprogress
oncanplay
oncanplaythrough

https://www.cnblogs.com/leinov/p/3896772.html

例子:用Vue寫出如下樣式
在這裡插入圖片描述
解析:
1 先寫出HTML樣式

<!-- 時間軸 -->
<div id="musicSlider">
	<div style="width: 15%; float: left;">
		<label v-text="$options.filters.formatSecond(audio.currentTime)"></label>
	</div>
	<div style="width: 70%; float: left;">
		<input type="range" style="padding: 0; margin: 0;width: 100%;" 
			v-model="sliderTime" min="0" max="100" @change="changeCurrentTime">
	</div>
	<div style="width: 15%; float: left;">
		<label v-text="$options.filters.formatSecond(audio.maxTime)"></label>
	</div>
</div>

<!-- 歌曲資訊 -->
<div id="audioInfo">
	<audio id="audio-1" :src="song.musicUrlAudio" ref="audio"  autoplay="autoplay"  onended="nextMusic()"
		@pause="onPause"
		@play="onPlay"
		@timeupdate="onTimeupdate"
		@loadedmetadata="onLoadedmetadata" >
	</audio>
</div>

左右兩邊的時間怎麼獲得呢?
v-text不解釋標籤,也就是直接輸出獲取的資料,v-text使用過濾器,通過$options.filters進行使用
v-text如何使用filters:https://jingyan.baidu.com/article/e52e36151dae2040c60c51f0.html

filters: {
	formatSecond(second = 0) {
      	return realFormatSecond(second);
    }
}
// 將整數轉換成 時:分:秒的格式
function realFormatSecond(second) {
  	var secondType = typeof second
  	if (secondType === 'number' || secondType === 'string') {
	    second = parseInt(second)
	    var mimute = Math.floor(second / 60)
	    second = second - mimute * 60
	    return ('0' + mimute).slice(-2) + ':' + ('0' + second).slice(-2)
  	} else {
	    return '00:00'
  	}
}

Vue的method方法裡面

// 當timeupdate事件大概每秒一次,用來更新音訊流的當前播放時間
onTimeupdate(res) {
  	this.audio.currentTime = res.target.currentTime;
  	this.sliderTime = parseInt(this.audio.currentTime / this.audio.maxTime * 100);			      	
},
onLoadedmetadata(res) {
	console.log(this)
	console.log(res)
  	this.audio.maxTime = parseInt(res.target.duration);
},
changeCurrentTime() {
  	this.$refs.audio.currentTime = parseInt(this.sliderTime / 100 * this.audio.maxTime)
},

打印出的this
在這裡插入圖片描述
audio.currentTime=> 列印 res.target.duration通過parseInt轉化為整數就是整首歌的時長
在這裡插入圖片描述
那,最左邊的那個時間怎麼變化,那個滑竿怎麼跟著變呢?
過濾器裡面返回了這個函式:realFormatSecond

解決進度條:
http://www.cnblogs.com/lalalagq/p/9961959.html
https://blog.csdn.net/fgdfgasd/article/details/82152482?utm_source=blogxgwz5
在這裡插入圖片描述
原始碼:

<!DOCTYPE HTML>
<html>

<head>
    <meta charset="utf-8">
    <title></title>
    <link rel="shortcut icon" href="images/fa.ico">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black">

    <style type="text/css">
        .mui-bar {
            background-color: white;
        }
        body {
            background-color: white;
            color: black;
        }
        #musicPlayBtns {
            position: fixed;
            bottom: 5%;
            width: 100%;
        }
        #musicSlider {
            position: fixed;
            bottom: 15%;
            width: 100%;
        }
        @media screen and (orientation: portrait) {
            #baseIndo {
                position: fixed;
                width: 100%;
                top: 5%;
            }
            #musicImage {
                position: fixed;
                width: 100%;
                top: 20%;
                /* bottom: 45%; */
            }
        }
        @media screen and (orientation: landscape) {
            #baseIndo {
                width: 50%;
                float: right;
                top: 1%;
            }
            #musicImage {
                width: 50%;
                float: left;
                /* top: 1%; */
            }
        }
        .mui-bar {
            height: 58px;
        }

        .mui-title {
            font-weight: 700;
        }

        .sub-title {
            font-size: 12px;
            font-weight: 400;
            line-height: 82px;
            position: absolute;
            display: block;
            width: 100%;
            margin: 0 -10px;
            padding: 0;
            text-align: center;
            white-space: nowrap;
            color: #000;
        }
        /* 控制進度條 */
		.slider {
			/* margin-top:100px; */
			width: 100%;
			position: relative;
			height: 24px;
			margin-bottom: 16px;
			display: flex;
			align-items: center;
			cursor: default;
			user-select: none;
			outline: none;
		}

		.slider-track {
			position: absolute;
			height: 2px;
			left: 0;
			right: 0;
			top: 50%;
			margin-top: -1px;
			background-color: #bec2c1;
		}

		.slider-fill {
			position: absolute;
			height: 2px;
			width: 100%;
			background-color: #888;
			left: 0;
			top: 50%;
			margin-top: -1px;
		}

		.slider-thumb {
			position: absolute;
			top: 50%;
			width: 12px;
			height: 12px;
			background-color: #888;
			color: #888;
			border-radius: 50%;
			transform: translate(-50%, -50%);
			cursor: pointer;
		}

    </style>
</head>

<body>
    <!-- https://github.com/wangduanduan/element-audio -->
    <div id="app">
        <div style="margin-top:60px;">
            <div style="text-align: center;">

                <!-- 顯示 -->
                <div id="musicImage">
                    <img width="65%" height="auto" style="border-radius:50%;" src="music.jpg" alt="" />
                </div>



                <!-- 時間軸 -->
                <div id="musicSlider">
					<div style="width: 15%; float: left;">
						<label v-text="$options.filters.formatSecond(audio.currentTime)"></label>
					</div>
					<div style="width: 70%; float: left;">
						<input type="range" style="padding: 0; margin: 0;width: 100%;" 
							v-model="sliderTime" min="0" max="100" @change="changeCurrentTime">
					</div>
					<div style="width: 15%; float: left;">
						<label v-text="$options.filters.formatSecond(audio.maxTime)"></label>
					</div>
				</div>
                <!-- 按鈕 -->
                <div id="musicPlayBtns">
					<div style="width: 45%; float: left;">
						<img width="30px;" height="auto" id="preBtn" src="images/pre1.png" alt="" @click="preMusic" />
					</div>
					<div style="width: 10%; float: left;">
						<img width="30px;" height="auto" id="playBtn" :src="audio.playing ? 'images/play1.png' : 'images/pause1.png'" alt="" @click="startPlayOrPause" />
					</div>
					<div style="width: 45%; float: left;">
						<img width="30px;" height="auto" id="nextBtn" src="images/next1.png" alt="" @click="nextMusic" />
					</div>
				</div>
                <!-- 歌曲資訊 -->
                <div id="audioInfo">
                     <!-- 此處的ref屬性,可以很方便的在vue元件中通過 this.$refs.audio獲取該dom元素 -->
                    <audio id="audio-1" ref="audio" autoplay="autoplay" controls src="http://192.168.188.1:8000/nwmsucms/music/musicfile_7295697c-04a0-47a3-8b74-b299192a86b6.mp3" 
                    @pause="onPause"
                    @play="onPlay"
                    @timeupdate="onTimeupdate"
                    @loadedmetadata="onLoadedmetadata"
                    @ended="nextMusic">
                    </audio>
                </div>
            </div>
        </div>
    </div>
    <script src="vue.min.js"></script>
    <script src="jquery.min.js"></script>
    <script type="text/javascript">
      
        // 將整數轉換成 時:分:秒的格式
        function realFormatSecond(second) {
            var secondType = typeof second
           if (secondType === 'number' || secondType === 'string') {
                second = parseInt(second)
                var mimute = Math.floor(second / 60)
                second = second - mimute * 60
                return ('0' + mimute).slice(-2) + ':' + ('0' + second).slice(-2)
            } else {
                return '00:00'
            }
        }

        var app = new Vue({
            el: '#app',
            data: {
                song: {},
                audio: {
                    // 該欄位是音訊是否處於播放狀態的屬性
                    playing: false,
                    currentTime: 0,
                    maxTime: 0,
                    minTime:0,
                    step:0.1
                },
                sliderTime: 0,         
            },
            created: function () {
                //var songJson = sessionStorage.getItem('songJson');
		// var chineseSongsJson = sessionStorage.getItem('chineseSongsJson');
		// var englishSongsJson = sessionStorage.getItem('englishSongsJson');
		// this.song = JSON.parse(songJson);
		// console.log(this.song)
		// this.chineseSongs = JSON.parse(chineseSongsJson);
		// this.englishSongs = JSON.parse(englishSongsJson);
            },
            mounted: function () {
               
            },
            methods:{
                // 控制音訊的播放與暫停
                startPlayOrPause() {
			      	return this.audio.playing ? this.pause() : this.play();
			    },
				play() {
		      		this.$refs.audio.play();
			    },
			    pause() {
			      	this.$refs.audio.pause();
			    },
                // 當音訊播放
			 	onPlay() {
			      	this.audio.playing = true;
		    	},
                // 當音訊暫停
			    onPause() {
			      	this.audio.playing = false;
			    },
                /* 音訊的時間顯示主要有兩部分,音訊的總時長和當前播放時間。可以從兩個事件中獲取

                loadedmetadata:代表音訊的元資料已經被載入完成,可以從中獲取音訊總時長
                timeupdate: 當前播放位置作為正常播放的一部分而改變,或者以特別有趣的方式,例如不連續地改變,可以從該事件中獲取音訊的當前播放時間,該事件在播放過程中會不斷被觸發 */

                // 當timeupdate事件大概每秒一次,用來更新音訊流的當前播放時間
			    onTimeupdate(res) {
			      	this.audio.currentTime = res.target.currentTime;
			      	this.sliderTime = parseInt(this.audio.currentTime / this.audio.maxTime * 100);			      	
			    },
                // 當載入語音流元資料完成後,會觸發該事件的回撥函式
                // 語音元資料主要是語音的長度之類的資料
				onLoadedmetadata(res) {
			      	this.audio.maxTime = parseInt(res.target.duration);
			    },
                // 拖動進度條,改變當前時間,index是進度條改變時的回撥函式的引數0-100之間,需要換算成實際時間
			    changeCurrentTime() {
		    	  	this.$refs.audio.currentTime = parseInt(this.sliderTime / 100 * this.audio.maxTime)
		    	},
		    	// 進度條格式化toolTip
				/* formatProcessToolTip(index = 0) {
					index = parseInt(this.audio.maxTime / 100 * index)
					return '進度條: ' + realFormatSecond(index)
				}, */

				handleTouchStart(e) {
					this.setValue(e.touches[0]);

					document.addEventListener('touchmove', this.handleTouchMove);
					document.addEventListener('touchup', this.handleTouchEnd);
					document.addEventListener('touchend', this.handleTouchEnd);
					document.addEventListener('touchcancel', this.handleTouchEnd);

					// e.preventDefault();
					// this.onDragStart(e);
				},
				handleTouchMove(e) {
					// console.log(e.changedTouches[0])
					this.setValue(e.changedTouches[0]);
				},
				handleTouchEnd(e) {
					this.setValue(e.changedTouches[0]);
					document.removeEventListener('touchmove', this.handleTouchMove);
					document.removeEventListener('touchup', this.handleTouchEnd);
					document.removeEventListener('touchend', this.handleTouchEnd);
					document.removeEventListener('touchcancel', this.handleTouchEnd);
					// this.onDragStop(e);
				},
				// 從點選位置更新 value
				setValue(e) {
					const $el = this.$el;
					const {
						maxTime,
						minTime,
						step
					} = this.audio;
					let value = (e.clientX - $el.getBoundingClientRect().left) / $el.offsetWidth * (maxTime - minTime);
					value = Math.round(value / step) * step + minTime;
					value = parseFloat(value.toFixed(5));

					if (value > maxTime) {
						value = maxTime;
					} else if (value < minTime) {
						value = minTime;
					}
					this.$refs.audio.currentTime = value;
				},

		    	preMusic() {
		    		this.audio.playing = false;
		    		var songIndex = this.chineseSongs.findIndex(x => x.id == this.song.id);
		    		var preIndex = 0;
		    		if(songIndex !== -1) {
		    			preIndex = (songIndex - 1) < 0 ? (this.chineseSongs.length - 1) : (songIndex - 1);
		    			this.song = this.chineseSongs[preIndex];
		    		} else {
		    			songIndex = this.englishSongs.findIndex(x => x.id == this.song.id)
		    			preIndex = (songIndex - 1) < 0 ? (this.englishSongs.length - 1) : (songIndex - 1);
		    			this.song = this.englishSongs[preIndex];
		    		}
		    		// this.readLyric();
		    	},
		    	nextMusic() {
		    		this.audio.playing = false;
		    		var songIndex = this.chineseSongs.findIndex(x => x.id == this.song.id);
		    		var nextIndex = 0;
		    		if(songIndex !== -1) {
		    			nextIndex = (songIndex + 1) >= this.chineseSongs.length ? 0 : (songIndex + 1);
						this.song = this.chineseSongs[nextIndex];						
		    		} else {
		    			songIndex = this.englishSongs.findIndex(x => x.id == this.song.id)
		    			nextIndex = (songIndex + 1) >= this.englishSongs.length ? 0 : (songIndex + 1);
		    			this.song = this.englishSongs[nextIndex];
		    		}
		    		// this.readLyric();
		    	},
            },
            filters: {
	        	formatSecond(second = 0) {
        	      	return realFormatSecond(second);
        	    }
	        }
        })

    </script>
</body>

</html>