html js弹幕功能

html js弹幕功能_第1张图片
效果如上

html
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
		<script charset="utf-8" src="//picture.52hrttpic.com/static/webapp/vue/vue.min.js" type="text/javascript">
		</script>
		<link rel="stylesheet" href="./css/index.css" />
		<script src="./js/update.js"></script>
	</head>
	<body>
		<div id="app">
			<div class="index" ref="index">
				<div class="btn stop" @click="toggelDanmu">{{isStop ? '开始弹幕' : '停止弹幕'}}</div>
				<div class="btn add" @click="adddanmu">添加弹幕</div>
			</div>
		</div>

	</body>
	<script src="./js/index.js"></script>
	
</html>
js
	function AddDanMuFn(option) {
	this.currentDanmuNum = 0; // 移动到实例属性
	this.option = option;
	this.elWidth = option.el.offsetWidth != 0 ? option.el.offsetWidth : document.querySelector('body').getBoundingClientRect().width;

	this.initFn = function(text, isAddDanmu) {
		let danmuName = 'danmu-' + this.randomString(6);
		let danmuLine = this.currentDanmuNum % (this.option.danmuLine || 3);
		let danmuNum = `danmu-${danmuLine}`;
		this.currentDanmuNum++;

		let danmuNumAllDom = document.querySelectorAll(`.${danmuNum}`);
		let newDomLeft = danmuNumAllDom.length > 0 ? this.calculateNewLeft(danmuNumAllDom) : this.elWidth;

		let div = document.createElement('div');
		// 手动添加的话 会有一个add 的类名 可以在css里 改变特定的样式
		div.className = `${danmuName} ${danmuNum} item ${isAddDanmu ? 'add' : ''}`;
		div.style.left = newDomLeft + 'px';
		div.innerText = text;
		(this.option.el || document.querySelector('body')).appendChild(div);

		let currentDom = document.querySelector(`.${danmuName}`);
		let divWidth = currentDom.offsetWidth;
		let divHeight = currentDom.offsetHeight;
		div.style.top = danmuLine * (divHeight + (this.option.marginTop || 10)) + 'px';

		// Create animation and store its ID
		let animationId = requestAnimationFrame(this.animationFn.bind(this, currentDom, divWidth, this.option
			.speed || 3));
		currentDom.animationId = animationId
	};

	this.animationFn = function(currentDom, divWidth, speed) {
		let rect = currentDom.getBoundingClientRect();
		if (rect.left + divWidth < 0) {
			cancelAnimationFrame(currentDom.animationId); // Correctly cancel animation
			currentDom.remove();
			return;
		}

		currentDom.style.left = rect.left - speed + 'px';
		let animationId = requestAnimationFrame(this.animationFn.bind(this, currentDom, divWidth, speed));
		currentDom.animationId = animationId;
	};

	this.stopAll = function() {
		let danmus = document.querySelectorAll('.item');
		for (let danmu of danmus){
			cancelAnimationFrame(danmu.animationId)
			danmu.remove();
		}
	};

	this.startAll = function() {
		let danmus = document.querySelectorAll('.item'); 
		for (let danmu of danmus) {
			if (danmu.animationId) { 
				let divWidth = danmu.offsetWidth;
				let speed = this.option.speed || 3;
				let animationId = requestAnimationFrame(this.animationFn.bind(this, danmu, divWidth, speed));
				danmu.animationId = animationId;

			}
		}
	};
    // 随机数
	this.randomInteger = function(a, b) {
		if (arguments.length === 1) {
			return Math.floor(Math.random() * a);
		} else if (arguments.length === 2) {
			return Math.floor(Math.random() * (b - a + 1) + a);
		}
		return 0;
	};
     // 随机值
	this.randomString = function(length) {
		length = length || 8; // Reasonable default length
		let chars = "ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678";
		let result = "";
		for (let i = 0; i < length; i++) {
			result += chars.charAt(Math.floor(Math.random() * chars.length));
		}
		return result;
	};
      
	this.calculateNewLeft = function(danmuNumAllDom) {
		let lastDom = danmuNumAllDom[danmuNumAllDom.length - 1];
		let lastDomWidth = lastDom.offsetWidth;
		let lastDomLeft = lastDom.getBoundingClientRect().left;
		let newDomLeft = lastDomWidth + lastDomLeft + (this.option.marginLeft || 10);
		return newDomLeft < this.elWidth ? this.elWidth : newDomLeft;
	};
}


var app = new Vue({
	el: '#app',
	data: {
		list: [{
				text: '山河无恙,国泰民安'
			},
			{
				text: '我爱你,中国!'
			},
			{
				text: '辉煌七十五载,山河锦绣灿烂。'
			},
			{
				text: '生日快乐,我的国!'
			},
			{
				text: '清澈的爱,只为中国!'
			},
			{
				text: '岁月悠悠,山河如画!'
			},
			{
				text: '我爱中华!'
			},
			{
				text: '75年风雨兼程,共筑中国梦!'
			},
			{
				text: '鹭岛金秋红旗展,国庆佳节同欢庆'
			},
			{
				text: '泱泱中华, 千古风华依旧'
			},
		],
		currentIndex: 0, // 当前弹幕列表的下标
		addDanmuInterval: null, // 添加弹幕的定时器
		isStop: false
	},
	mounted() {
		this.$nextTick(() => {
			// 创建实例 生成这个实例  要在页面完全渲染完成的时候  要不然 会获取不到 传入el的宽度
			// 这个弹幕的el css要设置成 position relative 
			// 每一个弹幕 都会有一个共同的class类名item  要设置成 position absolute 
			// white-space: nowrap; 文字要设置成 不换行 
			this.danmu = new AddDanMuFn({
				danmuLine: 5, // 多少行弹幕
				el: document.querySelector('.index'), // 在哪个div里添加弹幕
				marginLeft: 30, // 每个弹幕距离左边的距离
				speed: 3, // 速度
				marginTop: 10 // 每行弹幕上下的距离
			});
			this.list.forEach((item, index) => {
				this.danmu.initFn(this.list[index].text)
			})
			this.startAddDanmuFn()

		})
	},
	methods: {
		toggelDanmu() {
			if (this.isStop) {
				this.startDanmu()
			} else {
				this.stopDanmu()
			}
			this.isStop = !this.isStop
		},
		stopDanmu() {
			// 停止添加弹幕
			clearInterval(this.addDanmuInterval)
			this.danmu.stopAll()
		},
		startDanmu() {
			this.danmu.startAll()
			this.startAddDanmuFn()
		},
		adddanmu() {
		  // 自己添加的弹幕  第二个参数 为true  就是代表 是自己添加的弹幕 这个弹幕就会有一个add的类名
			this.danmu.initFn('自己添加的弹幕', true)
		},
		startAddDanmuFn() {
			this.addDanmuInterval = setInterval(() => {
				// 获取弹幕总数 如果超过20个 不添加弹幕
				let danmuAllNum = document.querySelectorAll('.item').length
				// if(danmuAllNum > 20) return
				this.danmu.initFn(this.list[this.currentIndex].text)
				this.currentIndex++
				if (this.currentIndex >= this.list.length) {
					this.currentIndex = 0
				}
			}, 1000)

		}
	},

})
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;
		white-space: nowrap;
		line-height: 10vw;
		&.add{
			background: red;
		}
		
	}
}

你可能感兴趣的:(javascript,html)