html js弹幕功能

效果如上

bash 复制代码
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>
bash 复制代码
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
		}
	},

})
bash 复制代码
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;
		}
	}
}
相关推荐
还是大剑师兰特12 分钟前
什么是尾调用,使用尾调用有什么好处?
javascript·大剑师·尾调用
Watermelo61733 分钟前
详解js柯里化原理及用法,探究柯里化在Redux Selector 的场景模拟、构建复杂的数据流管道、优化深度嵌套函数中的精妙应用
开发语言·前端·javascript·算法·数据挖掘·数据分析·ecmascript
m0_7482489435 分钟前
HTML5系列(11)-- Web 无障碍开发指南
前端·html·html5
m0_748235611 小时前
从零开始学前端之HTML(三)
前端·html
旭久2 小时前
SpringBoot的Thymeleaf做一个可自定义合并td的pdf表格
pdf·html·springboot
一个处女座的程序猿O(∩_∩)O3 小时前
小型 Vue 项目,该不该用 Pinia 、Vuex呢?
前端·javascript·vue.js
燃先生._.9 小时前
Day-03 Vue(生命周期、生命周期钩子八个函数、工程化开发和脚手架、组件化开发、根组件、局部注册和全局注册的步骤)
前端·javascript·vue.js
高山我梦口香糖10 小时前
[react]searchParams转普通对象
开发语言·前端·javascript
black^sugar11 小时前
纯前端实现更新检测
开发语言·前端·javascript