利用面向对象写弹幕效果
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.container {
width: 800px;
margin: 0 auto;
padding-bottom: 10px;
background-color: #dfdfdf;
}
#barrage {
position: relative;
height: 500px;
margin-bottom: 10px;
background-color: #000;
overflow: hidden;
}
#barrage .bar-item {
position: absolute;
left: 100%;
white-space: nowrap;
}
#msg {
margin-left: 10px;
width: 400px;
height: 30px;
border: 1px solid #999;
border-right: none;
box-sizing: border-box;
vertical-align: middle;
}
#msg+button {
padding: 0 10px;
height: 30px;
vertical-align: middle;
}
</style>
</head>
<body>
<div class="container">
<div id="barrage"></div>
<input type="text" id="msg"><button id="btn">发送</button>
</div>
<script src="js/utils.js"></script>
<script>
/*
【1】创建对象 (弹幕的文字)
【2】描述对象
静态属性:
在页面中存在的标签
弹幕的内容(文字)
文字的大小
文字的颜色
文字的位置
文字移动速度
动态方法:
init() 初始化的方法,一般用来写事件,获取元素,创建节点,调用方法
move() 文字移动的函数
removeEle() 当文字移动到 弹幕之外移出这个弹幕的元素
【3】操作对象
*/
// 创建对象
function Barrage(ele, content) {
this.ele = ele;
this.content = content;
this.fontSize = getRandom(12, 30);
this.color = getRandomColor();
this.top = getRandom(0, this.ele.offsetHeight - this.fontSize);
this.speed = getRandom(10, 20);
}
// 动态方法一般写在原型对象上面
Barrage.prototype.init = function() {
// 创建一个节点 span
this.span = document.createElement('span');
this.span.classList.add('bar-item');
this.span.innerHTML = this.content;
this.span.style.fontSize = this.fontSize + 'px';
this.span.style.color = this.color;
this.span.style.top = this.top + 'px';
this.ele.appendChild(this.span);
this.move()
}
// 弹幕移动效果
Barrage.prototype.move = function() {
let timer = setInterval(() => {
// 获取当前的left值
let styleLeft = parseInt(getStyle(this.span, 'left'));
console.log(styleLeft)
// 当当前的left值 小于 span元素宽度的负值时清除定时器,并且移出span元素
if (styleLeft <= -this.span.offsetWidth) {
clearInterval(timer);
this.removeEle();
}
move(this.span, {
left: styleLeft - this.speed
})
}, 80)
// let _this = this;
// let timer = setInterval(function () {
// // this指向的是window window 中没有span属性
// console.log(_this);
// let styleLeft = parseInt(getStyle(_this.span, 'left'));
// if (styleLeft <= -_this.span.offsetWidth) {
// clearInterval(timer);
// _this.removeEle();
// }
// move(_this.span, { left: styleLeft - _this.speed })
// }, 80)
}
// 当移动结束 把这个节点移出
Barrage.prototype.removeEle = function() {
// 移出span元素
this.span.remove()
}
// 获取页面中存在的标签
let barrage = document.querySelector('#barrage');
let btn = document.querySelector('#btn');
let msg = document.querySelector('#msg');
// 给btn绑定点击事件
btn.onclick = function() {
let b = new Barrage(barrage, msg.value);
b.init();
msg.value = '';
}
// 获取一个随机颜色
function getRandomColor() {
// var str = '0123456789abcdef';
// var res = '#'
// for (var i = 0; i < 6; i++) {
// // str[索引] 这个索引是随机,在0-15范围之间随机
// res += str[parseInt(Math.random() * 16)]
// }
var r1 = parseInt(Math.random() * 256);
var r2 = parseInt(Math.random() * 256);
var r3 = parseInt(Math.random() * 256);
var res = `rgb(${
r1},${
r2},${
r3})`
return res;
}
// 获取样式的方法
// 有两个参数
// 参数1:元素
// 参数2:csss属性
function getStyle(ele, attr) {
return style = window.getComputedStyle ? window.getComputedStyle(ele)[attr] : ele.currentStyle[attr]
}
// 封装一个事件监听的函数(兼容)
// 参数:事件源,事件类型,回调函数
function addEvent(ele, type, callback) {
if (ele.addEventListener) {
ele.addEventListener(type, callback);
} else {
ele.attachEvent('on' + type, callback)
}
}
// 动画函数
function move(ele, obj, callback) {
let speed;
let index = 0; //记录定时器的个数
// 循环对象创建定时器
for (let attr in obj) {
// 透明度的变化的时候 0-1
// console.log(attr);
index++;
// 清除上一次的定时器
clearInterval(ele[attr])
// 属性:attr
// 属性值:obj[key]
// box['width'] 给box这个dom元素添加一个 width属性(dom属性)
// dom 对象,以地址形式存储的,当上一次更改dom对象中的值,那么这次获取这个对象的时候是能拿到被更改之后的dom对象
ele[attr] = setInterval(() => {
// 把透明度的取值 改边为0-100的取值
// 0-1=====》0-100
let style;
if (attr == 'opacity') {
style = getStyle(ele, attr) * 100;
} else {
style = parseInt(getStyle(ele, attr));
}
speed = (obj[attr] - style) / 5;
speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);
style += speed;
if (attr === 'opacity') {
ele.style[attr] = style / 100;
} else {
ele.style[attr] = style + 'px';
}
if (style == obj[attr]) {
clearInterval(ele[attr]);
// 有多少个属性参数动画就会执行多少次
// 执行一次怎么?
// 没清除一次定时器,那么定时器的个数 -1
index--;
// 当定时器的个数 为0 的时候,说明所有动画执行完毕
if (index === 0) {
callback && callback();
}
}
}, 50)
}
}
</script>
</body>
</html>