使用vue控制video視訊和彈幕功能

weixin_43798882發表於2020-01-19
  • 2020-02-19
    前兩天想說練一下vue,就按照bilibili寫了一個demo(我第一次放這種模仿的頁面,如果有哪裡不合適的請告訴我哈),就寫了比較核心的首頁和視訊播放頁,包括控制視訊和彈幕渲染等等的,記錄一下。



先放一下最終效果

在這裡插入圖片描述
因為當時做的時候為了追求效果打的真實的名字,就手動打了一下碼


一、vue控制視訊播放


1. 引入視訊

這個非常簡單,就不用我說了吧~

<video id="video" src="video/video-horizontal.mp4" ref="video">
	您的瀏覽器不支援 video 標籤。
</video>

2. 播放 / 暫停功能

因為沒有我們想手動控制視訊的暫停或者播放,所以沒有加自動播放屬性,並且我們要繫結事件來控制視訊。

<!-- 開始 / 暫停按鈕 -->
<div class="play" @click="playOrPause()">
	<img v-if="!isPlay" src="img/goPlay.png" />
	<img v-cloak v-else src="img/pause.png" />
</div>
//  開始/ 暫停事件
  	playOrPause: function(){
  		if(this.isPlay){
  			$("#video").trigger("pause");
  		}else{
  			$("#video").trigger("play");	
  		}
  		this.isPlay = !this.isPlay;
  	}

沒有加自動播放屬性的視訊預設情況下是在暫停狀態的,所以isPlay的預設值是false。

data: {
   	isPlay: false
}

3. 獲取並及時更新視訊時間

//  獲取總時長
   	videoCanPlay: function(){
	    var duration =this.$refs.video.duration;
	    this.vcTotalTime = this.getFormatVideoTime(duration);
   	},
//  更新進度時間
   	videoTimeUpdate: function(){
	   	var currTime =this.$refs.video.currentTime;
	   	var duration =this.$refs.video.duration;
	   	this.vcCurrentTime = this.getFormatVideoTime(currTime);
	   	var pre = currTime / duration;
	   	this.vcProgress = pre*100;
   	},
//  格式化時間
   	getFormatVideoTime: function(time) {
           var time = time;
           var m = parseInt(time%3600/60),
               s = parseInt(time%60);
           m = m < 10 ? "0"+m : m;
           s = s < 10 ? "0"+s : s;
           return m+":"+s;
	}
<video id="video"  src="video/video-horizontal.mp4" ref="video"
	   @canplay="videoCanPlay()" 
	   @timeupdate="videoTimeUpdate()" >
	您的瀏覽器不支援 video 標籤。
</video>

然後在進度條和時間上也要展示最新的狀態,所以這裡也繫結上。

<div class="progress">
	<span class="alreadyRead" :style="{width: vcProgress*100/100 +'%'}"></span>
	<img @mousedown="move" :style="{left: vcProgress*100/100 +'%'}" src="img/progress.png" />
	<span class="unRead"></span>
</div>
<p v-cloak class="time">{{ vcCurrentTime }} / {{ vcTotalTime }}</p>

這裡繫結的move事件是用來拖動進度條調整時間的。
(另外在電腦上模擬手機端測試的話是不好用的,測試的話要切成PC才可以,這裡貼一下供大家參考哈。)

//  拖動進度條
    move(e){
      	let odiv = e.target;    //獲取目標元素
      	//算出滑鼠相對元素的位置
      	let disX = e.clientX - odiv.offsetLeft;
      	let disY = e.clientY - odiv.offsetTop;
      	document.onmousemove = (e)=>{    //滑鼠按下並移動的事件
	        //用滑鼠的位置減去滑鼠相對元素的位置,得到元素的位置
	        let left = e.clientX - disX;  
	        let top = e.clientY - disY;
	        //繫結元素位置到positionX和positionY上面
	        this.positionX = top;
	        this.positionY = left;
	        //移動當前元素
	        odiv.style.left = left + 'px';
	        odiv.style.top = top + 'px';
      	};
      	document.onmouseup = (e) => {
	        document.onmousemove = null;
	        document.onmouseup = null;
      	};
    }

4. 播放完成 / 重放

播放完成後的效果圖先貼一下

在這裡插入圖片描述

//	播放完成
	videoEnd: function(){
		$(".player-ended").css('display',"flex");
	},
//	重播
	replay: function(){
		$(".player-ended").hide();
		$("#video").trigger("play");
	}

重播按鈕上直接繫結replay就可以了,播放完成這樣繫結

<video id="video"  src="video/video-horizontal.mp4" ref="video"
	   @canplay="videoCanPlay()" 
	   @timeupdate="videoTimeUpdate()" 
	   @ended="videoEnd()">
	您的瀏覽器不支援 video 標籤。
</video>


二、彈幕功能


1. 新增彈幕容器

容器和video相對定位就可以了,就不貼程式碼了。

<div class="player-barrage">
	<ul class="roll"></ul>
	<ul class="center"></ul>
</div>

2. 彈幕列表

這裡的彈幕分為滾動和居中兩種,
一般來說應該是在初始化的時候在介面獲取的,我這裡自己練習,就寫成固定的了。
canAdd:用來判斷是否已經新增過了,已經新增過的彈幕不再重複新增了。
time:彈幕出現時間。
color:彈幕顏色。
cont:彈幕內容。

data:{
   	rollBarrageIndex: 0,		//用來固定位置的
   	rollBarrageList:[{		//滾動彈幕
   		canAdd: true,
   		time: '00:00',
   		color: '#fcf044',
   		cont: '1測試彈幕測試幕測試彈幕測試彈幕1'
   	},{
   		canAdd: true,
   		time: '00:00',
   		color: '#ffffff',
   		cont: '11測試彈幕測試彈幕測試彈幕幕測試彈幕測試彈幕測試彈幕測試彈幕測試彈幕1'
   	}],
    	
   	centerBarrageIndex: 0,
   	centerBarrageList:[{		//頂部居中彈幕
   		canAdd: true,
   		time: '00:00',
   		color: '#ffffff',
   		cont: '00000000000000000000000'
   	},{
   		canAdd: true,
   		time: '00:00',
   		color: '#e82624',
   		cont: '1111111111111111111111111111111111111111111111111'
   	}]
}

3. 在頁面中渲染彈幕

在這裡先說下哈,bilibili的APP的彈幕相關功能真的是很非常完善的,要是用H5做很麻煩,
比如暫停視訊時彈幕應該也跟隨暫停,這個功能使用canvas更方便做出來,
在這裡因為只是練習demo,彈幕的動效和渲染我都是用定時器做的,沒辦法完成到對應暫停,只做了些基礎的功能。

//	更新滾動彈幕
    updataRollBarrage: function(){
   		var _this = this;
   		$(_this.rollBarrageList).each(function(i,item){
   			//當符合出現彈幕時間,並且彈幕沒有被新增過時,新增彈幕
   			if(item.time == _this.vcCurrentTime && item.canAdd){
   				//彈幕要固定top是因為清除已經展示過的彈幕會讓後面的彈幕往上移
   				$(".player-barrage .roll").append("<li style='top: " + _this.rollBarrageIndex*21 + "px; color: " + item.color + ";'><p>" + item.cont + "</p></li>");
   				//選中當前新增的彈幕
   				var obj = $(".player-barrage .roll li").last();
   				//當前彈幕勻速向左移動
   				var speed = obj.width() * 7;
   				$(obj).find('p').animate({left:"-100%"}, speed, "linear",function(){
   					//這個時候彈幕已經跟螢幕左對齊了,然後再讓父元素移出螢幕
   					//不用之前的speed是為了和之前的速度保持一致
   					var speedBox = $(obj).parent().width() * 7; 
   					$(obj).animate({left:"0%"}, speedBox, "linear",function(){
   						//父元素也移出螢幕後,可以清除當前彈幕
   						$(obj).remove();       						
   					})
   				});
   				//我這裡是預設展示五行滾動彈幕
   				//如果想根據同一時間彈幕數量的多少決定展示幾行彈幕,可以新增當前時間的判斷,但是在demo裡面我就不寫這麼複雜了
   				_this.rollBarrageIndex = (_this.rollBarrageIndex >= 4) ? (_this.rollBarrageIndex - 4) : (_this.rollBarrageIndex + 1);
   				//已新增過的彈幕不再新增了
   				item.canAdd = false;
   				//終止each迴圈
   				return false;
   			}
   		})
   	},
//	更新居中彈幕
    updataCenterBarrage: function(){
    	//大部分邏輯和滾動彈幕一樣,動效直接在css裡面寫,所以這裡只要定時清除就可以了
   		var _this = this;
   		$(_this.centerBarrageList).each(function(i,item){
   			if(item.time == _this.vcCurrentTime && item.canAdd){
   				$(".player-barrage .center").append("<li style='top: " + _this.centerBarrageIndex*21 + "px; color: " + item.color + ";'><p>" + item.cont + "</p></li>");
   				var obj = $(".player-barrage .center li").last();
   				//我這裡設定3秒後自動清除
   				//如果想根據內容多少來判斷展示時間,獲取一下寬度,乘以一個係數就可以了,別忘了設定最短時間
				setTimeout(function(){
 						$(obj).remove(); 
				},3000)
   				_this.centerBarrageIndex = (_this.centerBarrageIndex >= 4) ? (_this.centerBarrageIndex - 4) : (_this.centerBarrageIndex + 1);
   				item.canAdd = false;
   				return false;
   			}
   		})
   	}

然後這兩個方法都在更新進度時間中呼叫就可以了

//  更新進度時間
   	videoTimeUpdate: function(){
    	var currTime =this.$refs.video.currentTime;
    	var duration =this.$refs.video.duration;
    	this.vcCurrentTime = this.getFormatVideoTime(currTime);
    	var pre = currTime / duration;
    	this.vcProgress = pre*100;
    	//呼叫渲染彈幕方法
    	this.updataRollBarrage();
    	this.updataCenterBarrage();
	}

然後在重放的時候,也別忘了重新設定可以被新增

//	重播
	replay: function(){
		console.log("replay");
		$(".player-ended").hide();
		$("video").trigger("play");	
		//清除當前螢幕上的彈幕
		$(".player-barrage li").remove();
		//可重新新增彈幕
		$(this.rollBarrageList).each(function(i,item){
			item.canAdd = true;
		})
		$(this.centerBarrageList).each(function(i,item){
			item.canAdd = true;
		})
	}


相關文章