html js弹幕功能

news2024/11/18 12:27:17

在这里插入图片描述
效果如上

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;
		}
	}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2066132.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[C语言]-基础知识点梳理-编译、链接、预处理

前言 各位师傅大家好&#xff0c;我是qmx_07,今天来给大家讲解以下程序运行会经历哪些事情 翻译环境和运⾏环境 在ANSIC的任何⼀种实现中&#xff0c;存在两个不同的环境 第1种是翻译环境&#xff0c;在这个环境中源代码被转换为可执⾏的机器指令&#xff08;⼆进制指令&a…

[FSCTF 2023]ez_php2

[FSCTF 2023]ez_php2 点开之后是一段php代码&#xff1a; <?php highlight_file(__file__); Class Rd{public $ending;public $cl;public $poc;public function __destruct(){echo "All matters have concluded";die($this->ending);}public function __call…

django宿舍管理系统 ---附源码98595

目 录 摘要 1 绪论 1.1 研究背景与意义 1.2 国内外研究现状 1.3论文结构与章节安排 2 宿舍管理系统系统分析 2.1 可行性分析 2.2 系统流程分析 2.2.1 数据增加流程 2.2.2 数据修改流程 2.2.3 数据删除流程 2.3 系统功能分析 2.3.1 功能性分析 2.3.2 非功能性分析…

vue vite创建项目步骤

1. 创建vue项目 node版本需18以上 不然报错 npm init vuelatest2. 项目配置 配置项目的icon配置项目的标题配置jsconfig.json 3. 项目目录结构划分 4.css样式的重置 npm install normalize.cssreset.css html {line-height: 1.2; }body, h1, h2, h3, h4, ul, li {padding…

aspose-words将tinymce中的换页符转换为word的换页符

aspose-words版本&#xff1a;21.1 java&#xff1a;1.8 tinymc&#xff1a;5.0.16 public void convertPageBreak() throws Exception{String sourceHtml "hello<!-- pagebreak -->world";sourceHtml sourceHtml.replaceAll("<!-- pagebreak -->…

鸿蒙崛起,前端/Java人才如何搭上这趟技术快车?

在科技飞速发展的今天&#xff0c;鸿蒙系统的崛起犹如一颗璀璨的新星&#xff0c;照亮了技术领域的新航道。对于前端和 Java 人才来说&#xff0c;这不仅仅是一个新的挑战&#xff0c;更是一次搭乘技术快车、实现职业飞跃的绝佳机遇。 一、鸿蒙崛起之势 鸿蒙系统自诞生以来&…

开放式耳机是什么意思?开放式对比入耳式耳机的音质更通透

开放式耳机是一种无需入耳的蓝牙耳机。它主要提供的是一种自然、开放的音频体验&#xff0c;并且无需封耳&#xff0c;能维持佩戴者对外界的感知和环境的联系。这种耳机并不需要深入耳道&#xff0c;但又能清晰听清耳机传来的内容&#xff0c;所以在佩戴方面会更加舒适。 开放…

告别本地硬件烦恼,一分钟教你用云端部署玩Stable Diffusion!

Stable diffusion有两种部署方式&#xff0c;分别是本地部署和云端部署。 本地部署需要把程序安装到自己的电脑上&#xff0c;因此对设备&#xff08;尤其是显卡显存&#xff09;要求比较高&#xff0c;但很多小伙伴反映自己设备不到位&#xff0c;升级设备费用成本过高&#…

【学习笔记】8、脉冲波形的变换与产生

本章简略记录。 8.1 单稳态触发器&#xff08;脉冲触发&#xff09; 单稳态触发器 应用于 &#xff1a;&#xff08;1&#xff09;脉冲整型&#xff08;2&#xff09;脉冲延时 &#xff08;3&#xff09;定时 单稳态触发器的工作特性&#xff1a; 没有触发脉冲作用时&#xf…

【EI会议征稿通知】 第四届航空航天、空气动力学与机电工程国际学术会议(AAME 2025)

第四届航空航天、空气动力学与机电工程国际学术会议&#xff08;AAME 2025&#xff09; 2025 4th International Conference on Aerospace, Aerodynamics and Mechatronics Engineering 会议将围绕“航天航空科学”、“空气动力学”、“机电工程”、“飞行器技术”等主题展开讨…

为什么制造企业智能化升级需要MES管理系统

在制造业的数字化转型浪潮中&#xff0c;MES管理系统的智能化升级扮演着至关重要的角色&#xff0c;它不仅重新定义了生产管理的边界&#xff0c;还为企业带来了前所未有的竞争力与可持续发展动力。本文将从数据赋能、人机深度融合、资源优化及生态协同四个维度&#xff0c;探讨…

ARM工作模式

ARM ARM架构ARM七个工作模式寄存器异常向量表存储格式&#xff08;内存大小端&#xff09;汇编指令 ARM架构 RAM&#xff1a;随机访问存储器 ROM&#xff1a;只读访问存储器 AHB&#xff1a;先进高速总线 APB&#xff1a;先进外设总线 USB&#xff1a;统一串行总线 norflash&am…

公司如何保护源代码不被员工泄漏?

保护源代码不被员工泄漏的方法&#xff1a; 1、验证&#xff1a;第三方身份验证&#xff0c;能减少账号泄密的风险&#xff1b; 2、法律保护&#xff1a;签署法律文件&#xff0c;可以一定程度上的防止员工主动泄密&#xff1b; 3、隔离控制&#xff1a;实施网络隔离&#x…

UV LED供电为什么要选择使用恒流驱动电源

LED为何一定要恒流供电? 在讨论此议题之前&#xff0c;什么是电源的恒流恒压&#xff1f; 什么是电源的恒流恒压   恒流&#xff0c;就是输出电流是恒定的&#xff0c;但电源电流却不是固定的&#xff0c;标称的电压只是安全上限&#xff1b;恒压&#xff0c;就是输出电压是…

TQRFSOC开发板47DR,100G光口自环测试

本实例将演示如何在RFSOC 47DR开发板上&#xff0c;实现100G光口自环测试。此测试使用光口自环模块实现硬件互联&#xff0c;FPGA中进行25Gbps收发校验&#xff0c;通过vivado的硬件管理器烧写比特流&#xff0c;查看传输误差与眼图。 开发板启动模式设置为JTAG模式&#xff0c…

不用再找了,国内无限制使用GPT 4o的方法【2024年9月 亲测好用】

都知道ChatGPT很强大&#xff0c;聊聊天、写论文、搞翻译、写代码、写文案、审合同等等&#xff0c;无所不能~ 那么到底怎么使用呢&#xff1f;其实很简单了&#xff0c;国内AI产品发展也很快&#xff0c;很多都很好用了~ 我一直在用&#xff0c;建议收藏下来~ 有最先进、最…

SolidityFoundry Merkle Airdrop

Merkle airdrop Merkle Tree&#xff0c;也叫默克尔树或哈希树&#xff0c;是区块链的底层加密技术&#xff0c;被比特币和以太坊区块链广泛采用。Merkle Tree允许对大型数据结构的内容进行有效和安全的验证&#xff08;Merkle Proof&#xff09;。对于有N个叶子结点的Merkle T…

框架——MyBatis的参数传递,基本的增删改

MyBatis环境搭建步骤&#xff08;超全解析&#xff01;&#xff01;&#xff01;&#xff09;&#xff1a; http://t.csdnimg.cn/VDMjDhttp://t.csdnimg.cn/VDMjD 1.参数传递 在AdminDao类中写下面两个方法 单个参数直接传递 &#xff1a; //根据id查询管理员对象 Admin fin…

C语言:函数详解(2)

目录 一、数组做函数参数 二、嵌套调用和链式访问 2.1 嵌套调用 2.2 链式访问 三、函数的声明和定义 3.1 单个文件 3.2 多个文件 一、数组做函数参数 在使用函数解决问题的时候&#xff0c;难免会将数组作为参数传递给函数&#xff0c;在函数内部对数组进行操作。 比如…

推荐大模型书籍|《扩散模型从原理到实战》

就在几年前&#xff0c;“通用人工智能”(Artificial General Inte11igence&#xff0c;AGI)似乎还是一个只存在于科幻小说中的概念&#xff0c;在现实中的实现方法仍在探索中。然而到了2022年&#xff0c;基于大语言模型的AIGC(AI Generated Content)领域的快速发展&#xff0…