效果如上
html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<script charset="utf-8" src="https://unpkg.com/vue@2.6.14/dist/vue.min.js" type="text/javascript">
</script>
<link rel="stylesheet" href="./css/index.css" />
</head>
<body>
<div id="app">
<div class="index" ref="index">
<div class="btn stop" @click="stopDanmu">停止弹幕</div>
<div class="btn add" @click="adddanmu">添加弹幕</div>
</div>
</div>
</body>
<script src="./js/index.js"></script>
</html>
js
var app = new Vue({
el: '#app',
data: {
list: [{
text: '山河无恙,国泰民安'
},
{
text: '我爱你,中国!'
},
{
text: '辉煌七十五载,山河锦绣灿烂。'
},
{
text: '生日快乐,我的国!'
},
{
text: '清澈的爱,只为中国!'
},
{
text: '岁月悠悠,山河如画!'
},
{
text: '我爱中华!'
},
{
text: '75年风雨兼程,共筑中国梦!'
},
{
text: '鹭岛金秋红旗展,国庆佳节同欢庆'
},
{
text: '泱泱中华, 千古风华依旧'
},
],
windowWidth: '', // 屏幕的宽度
marginLeft: 20, // 每一个距离左边的距离
currentIndex: 0, // 当前弹幕列表的下标
timeList: [], // 每一个弹幕的定时器
currentDanmuNum: 0, // 当前的弹道
addDanmuInterval:null, // 添加弹幕的定时器
},
mounted() {
this.$nextTick(() => {
this.windowWidth = document.querySelector('body').offsetWidth
this.addDanmuInterval = setInterval(() => {
// 获取弹幕总数 如果超过20个 不添加弹幕
let danmuAllNum = document.querySelectorAll('.item').length
if(danmuAllNum > 20) return
this.addDanMuFn(this.list[this.currentIndex].text)
this.currentIndex++
if (this.currentIndex >= this.list.length) {
this.currentIndex = 0
}
}, 1000)
this.list.forEach((item, index) => {
this.addDanMuFn(this.list[index].text)
})
// console.log(this.windowWidth);
})
},
methods: {
adddanmu() {
this.addDanMuFn('添加新的弹幕', true)
},
stopDanmu() {
// console.log(this.timeList);
this.timeList.forEach(item => {
clearInterval(item)
// console.log(item);
})
clearInterval(this.addDanmuInterval)
},
addDanMuFn(text, isAddDanmu) {
// 这里有个问题 添加太多计时器 就会错位 所以 弹幕量控制在 20以内
this.$nextTick(() => {
// 创建随机且唯一的弹幕类名id
let danmuName = 'danmu-' + this.randomString(6);
// console.log(danmuName);
// 生成弹幕的弹道 -- 随机弹道
// let danmuNum = 'danmu-' + this.randomNum(0, 4)
// 生成弹幕的弹道 -- 排序
let danmuNum = 'danmu-' + this.currentDanmuNum;
this.currentDanmuNum += 1
if (this.currentDanmuNum > 4) {
this.currentDanmuNum = 0
}
// console.log(danmuNum);
// 获取 单前弹道的 所有元素
let danmuNumAllDomNama = `.${danmuNum}`;
let danmuNumAllDom = document.querySelectorAll(danmuNumAllDomNama)
// 获取index元素
let indexDom = document.querySelector('.index')
// 判断当前弹道是否有元素
if (danmuNumAllDom.length > 0) {
// 获取最后一个元素
let lastDom = danmuNumAllDom[danmuNumAllDom.length - 1]
// 获取最后一个元素 本身的宽度
let lastDomWidth = lastDom.offsetWidth;
// 获取最后一个元素 距离左边的距离
let lastDomLeft = lastDom.getBoundingClientRect().left;
// 新的元素距离左边的距离
let newDomLeft = lastDomWidth + lastDomLeft + this.marginLeft;
if (newDomLeft < this.windowWidth) {
newDomLeft = this.windowWidth
}
// 创建一个新的div
let div = document.createElement('div');
if (isAddDanmu) {
div.className = `${danmuName} ${danmuNum} item add`
} else {
div.className = `${danmuName} ${danmuNum} item`
}
div.style.left = newDomLeft + 'px';
div.innerText = text;
indexDom.appendChild(div);
let currentDom = document.querySelector(`.${danmuName}`)
let divWidth = currentDom.offsetWidth;
danmuName = setInterval(() => {
currentDom.style.left = currentDom.getBoundingClientRect().left - 1 +
'px';
if (currentDom.getBoundingClientRect().left < -divWidth) {
clearInterval(danmuName)
currentDom.remove()
let index = this.timeList.findIndex(item => item == danmuName)
this.timeList.splice(index,1)
danmuName = null
index = null
}
}, 10)
this.timeList.push(danmuName)
} else {
// 单前弹道没有元素
let newDomLeft = this.windowWidth;
// 创建一个新的div
let div = document.createElement('div');
if (isAddDanmu) {
div.className = `${danmuName} ${danmuNum} item add`
} else {
div.className = `${danmuName} ${danmuNum} item`
}
div.style.left = newDomLeft + 'px';
div.innerText = text;
indexDom.appendChild(div);
let currentDom = document.querySelector(`.${danmuName}`)
let divWidth = currentDom.offsetWidth;
danmuName = setInterval(() => {
currentDom.style.left = currentDom.getBoundingClientRect().left - 1 +
'px';
if (currentDom.getBoundingClientRect().left < -divWidth) {
clearInterval(danmuName)
currentDom.remove()
let index = this.timeList.findIndex(item => item == danmuName)
this.timeList.splice(index,1)
danmuName = null
index = null
}
}, 10)
this.timeList.push(danmuName)
// console.log(div);
}
})
},
randomNum(a, b) {
switch (arguments.length) {
case 1:
return parseInt(Math.random() * a + 1, 10);
case 2:
return parseInt(Math.random() * (b - a + 1) + a, 10);
default:
return 0
}
},
randomString(a) {
a = a || 32;
var b = "";
for (i = 0; i < a; i++)
b += "ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678".charAt(Math.floor(48 * Math.random()));
return b
}
},
})
css
*{
margin: 0;
padding: 0;
}
.index{
width: 100vw;
height: 100vh;
background: #fff;
position: relative;
overflow: hidden;
.btn{
position: absolute;
bottom: 0;
width: 50vw;
height: 30vw;
font-size: 4vw;
text-align: center;
line-height: 30vw;
&.stop{
left: 0;
}
&.add{
right: 0;
}
}
.item{
height: 10vw;
padding: 0 3vw;
border-radius: 10vw;
background-color: gainsboro;
color: #fff;
font-size: 4vw;
display: inline-block;
position: absolute;
text-wrap: nowrap;
line-height: 10vw;
&.add{
background: red;
}
&.danmu-0{
top: 0;
}
&.danmu-1{
top: 12vw;
}
&.danmu-2{
top: 24vw;
}
&.danmu-3{
top: 36vw;
}
&.danmu-4{
top: 48vw;
}
}
}