vue+node.js+mysql實現視訊彈幕功能
阿新 • • 發佈:2018-12-06
主體html結構
<div class="vedio-container"> <div class="barrage-container-wrap" ref="barWrapper"> <div class="video-wrapper"> <common-video @watchCurrent="watchCurrentTime"></common-video> </div> <div class="barrage-container" ref="bar"></div> </div> <div class="input-wrapper"> <input v-model="barrageInnerText" type="text"> <div @click="send">傳送彈幕</div> </div> </div>
主要是:
<div class="barrage-container-wrap" ref="barWrapper">
<div class="video-wrapper">
<common-video @watchCurrent="watchCurrentTime"></common-video>
</div>
<div class="barrage-container" ref="bar"></div>
</div>
解釋:
- barrage-container-wrap是最外層容器,包裹著video和彈幕層div
- video-wrapper是包裹著一個基礎元件,commonVideo,監聽一個watchCurrent的事件,這個事件主要用於,基礎元件的video傳送當前視訊播放時間給父元件,父元件根據當前時間看是否有相應的彈幕,選擇性發出
- barrage-container是彈幕層div,彈幕主要在這裡顯示
- 注意:由於彈幕層div的z-index必須要大於video才可以顯示彈幕,所以commonVideo元件的video的controls元件要自己根據API設定,z-index大小:controls浮層>彈幕層>video,這樣才可以既能控制,又能看彈幕,又能看視訊
commonVideo元件html
<template>
<div class="common-video">
<video id="mycommonVideo" src="./../../assets/test.mp4"></video>
<div class="bottom-controls">
<span @click="changeStatus">{{playText}}</span>
<div class="progress-bar" ref="progressBar" @click="setBar">
<div class="progress-bar-active" ref="progressBarInner"></div>
</div>
<span class="time">{{currentT}} / {{allTime}}</span>
<span @click="addYinliang">音量+</span>
<span @click="decreaseYinliang">音量-</span>
<span @click="allScreen">全屏</span>
</div>
</div>
</template>
主要CSS
.vedio-container {
width: 80%;
height: 7rem;
margin: 0 auto;
font-size: 0.14rem;
margin-bottom: 1rem;
}
.barrage-container-wrap {
width: 100%;
height: 7rem;
position: relative;
overflow: hidden;
}
.barrage-container {
position: absolute;
top: 0;
left: 0;
right: 0;
z-index: 1;
bottom: 30px;
cursor: default;
user-select: none;
}
.barrage-item {
position: absolute;
top: 0;
left: 100%;
white-space: nowrap;
cursor: pointer;
color: #fff;
}
解釋:
1rem = 100px(自己設定),barrage-item是彈幕item
主要資料段
data() {
return {
barrageArray: [ //假彈幕資料
{
time: '5',
text: '秋天愛美麗'
},
{
time: '3',
text: '2'
},
{
time: '11',
text: 'winter has come'
}
],
barrageColorArray: [ //彈幕顏色
'#0099CC', '#333333', '#009966', '#FFFF66', '#9933FF', '#FFFF99', '#CCCCFF', '#CC9933', '#FFFF66'
],
barrageInnerText: '', //彈幕內容
currentTime: 0, //彈幕時間
}
}
主要js程式碼
初始化dom
this.barrageBoxWrap = this.$refs.barWrapper
this.barrageBox = this.$refs.bar
this.barrageWidth = parseInt(this.barrageBoxWrap.offsetWidth)
this.barrageHeight = parseInt(this.barrageBoxWrap.offsetHeight)
父元件中:按下按鈕傳送input框中的內容 send方法
send() {
this.createBarrage(this.barrageInnerText, true) //製作彈幕
usersModel.sendBarrage({ //向後臺傳送post請求,傳送當前視訊時間,彈幕內容,儲存到資料庫中
time: this.currentTime,
content: this.barrageInnerText
}).then((res)=>{
console.log(res)
})
this.barrageInnerText = ''
}
createBarrage方法,引數1:彈幕內容,引數2:是否隨機距離
createBarrage(msg, isSendMsg) {
//生產dom結點
let divNode = document.createElement('div')
divNode.innerHTML = msg
divNode.classList.add('barrage-item')
this.$refs.barWrapper.appendChild(divNode)
//設定偏離距離
var barrageOffsetLeft = this.getRandom(this.barrageWidth, this.barrageWidth * 2) //可設定隨機距離
barrageOffsetLeft = isSendMsg ? this.barrageWidth : barrageOffsetLeft //不隨機則就在距右邊0px
var barrageOffsetTop = this.getRandom(10, this.barrageHeight - 40) //彈幕的高度
var barrageColor = this.barrageColorArray[Math.floor(Math.random() * (this.barrageColorArray.length))] //彈幕的顏色
//執行並初始化滾動
this.initBarrage(divNode, {
left: barrageOffsetLeft,
top: barrageOffsetTop,
color: barrageColor
})
}
getRandom方法
getRandom(start, end) {
return start + (Math.random() * (end - start))
}
initBarrage方法,初始化彈幕元素,引數1:彈幕dom,引數2:距離引數物件
initBarrage(el, obj) {
obj.top = obj.top || 0
obj.class = obj.color || '#fff'
el.style.left = obj.left + 'px'
el.style.top = obj.top + 'px'
el.style.color = obj.color
//新增屬性
el.distance = 0
el.width = ~~window.getComputedStyle(el).width.replace('px','')
el.timer = null
this.barrageAnimation(el)
}
barrageAnimation方法,讓彈幕動起來
barrageAnimation(el) {
let that = this
this.move(el)
if (Math.abs(el.distance) < el.width + el.offsetLeft) { //如果移動的距離小於彈幕的長度+外部div的寬度,則不斷移動
el.timer = requestAnimationFrame(function () {
that.barrageAnimation(el);
})
} else {
cancelAnimationFrame(el.timer);
//刪除節點
el.parentNode.removeChild(el);
}
}
解釋:
cancelAnimationFrame,requestAnimationFrame是h5的請求動畫幀的方法,遞迴實現平滑節能的動畫效果
move方法
move(el) {
el.distance--;
el.style.transform = 'translateX('+el.distance+'px)'; //設定transform,平滑實現
el.style.webkitTransform = 'translateX('+el.distance+'px)';
}
這樣基本可以實現傳送彈幕的效果了
從後臺接受資料,並在相應的時間進行傳送
首先設計的資料庫表很簡單:
id欄位,time欄位,content欄位
簡單的sql語句和node.js程式碼不貼出來了,如有需要則私聊我,這裡主要介紹思想
思想是:子元件的video,向父元件emit事件,每一秒就傳遞當前video的currentTime,父元件根據函式看時間是否吻合,如果吻合,則用send方法傳送彈幕
子元件JS程式碼:
//每個一秒設定進度條並設定時間
setProgressBar() {
let outerBarWidth = this.$refs.progressBar.offsetWidth
this.oneTimer = setInterval(()=>{
this.setTimes(this.videoDom.currentTime,'current')
this.currentTimeNumber = this.videoDom.currentTime
let baifenbi = this.currentTimeNumber / this.allTimeNumber
let innerWidth = baifenbi * outerBarWidth
this.$refs.progressBarInner.style.width = innerWidth + 'px'
this.$emit('watchCurrent',Math.floor(this.currentTimeNumber)) //主要的程式碼是這一行,上面是設定conrtols的程式碼
},1000)
}
父元件程式碼:
<!-父元件監聽-->
<common-video @watchCurrent="watchCurrentTime"></common-video>
barrageArray: [ //假彈幕資料,在created的時候連線後臺,把資料覆蓋上去
{
time: '5',
text: '秋天愛美麗'
}
]
//子元件傳遞的每一秒,看這一秒是否有彈幕
watchCurrentTime(seconds) {
this.currentTime = seconds
let barlen = this.barrageArray.length
let that = this
for(let i =0;i<barlen;i++){
let item = this.barrageArray[i]
if(!item){
continue
}
if(item.time == seconds){
that.createBarrage(item.text,true)
// that.barrageArray.splice(i,1)
}
}
}
//不知道這個演算法寫的好不好,有想過把已經顯示的彈幕splice掉,但是這樣重新點選到相應的時間就看不到彈幕了,如果有更好的方法也可以改為你自己的演算法哦
至此大概的功能的實現了,自己做的video controls的功能沒有貼出來
原始碼:
請私聊我要哦
參考
https://blog.csdn.net/qq_32849999/article/details/81031234
裡面更加詳細,如有需要可以進去看看