最近在学习js的过程中,学习了运动函数的封装。
在日常学习工作中经常需要设置一些运动效果,此时就需要用到运动函数,提前封装好一个运动函数可以在需要做其他的效果的时候进行引用,极大提高了重用率,大大增加我们的效率。
下面将分为三个步骤展示 :
一是运动 函数的封装,
二是编写一个小球运动效果,帮助对运动函数的理解,
最后编写一个稍复杂的烟花效果的页面,展示对封装的运动函数的应用。
首先,封装一个运动函数:
我们知道,运动三要素:谁运动(对象),属性,目标
emmm,算了,废话不多说,直接展示demo(思路逻辑都写在注释中,不再赘述)
/*****封装一个运动函数*****/
var times = '';
function move(ele, target, way) {
//事先清除一下定时器
clearInterval(times);
times = setInterval(function () {
//先设置一个开关,定义初始值为true
var onOff = true;
//用for in 循环遍历运动的属性(方向、目标),即遍历(target)
for (let attr in target) { //attr表示运动的属性
//获取元素运动到哪里了的实时值
//想要获取实时值,就要在外部封装一个获取实时位置的函数方法,然后再
通过调用这个方法获取实时值并保存
let now = parseInt(getPos(ele, attr))
//计算此时速度的值(speed)
let speed = (target[attr] - now) / 10;
//取整数(向上向下取整)
speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);
//设置一个开关的状态(true)用来表示元素运动到终点
if (now == target[attr]) {
onOff = true;
}
//让元素运动
ele.style[attr] = now + speed + 'px';
}
//判断开关的状态,如果到达终点则停止定时器
for (var tip in target) {
if (target[tip] !== parseInt(getPos(ele, tip))) {
onOff = false;
break;
}
}
if (onOff) {
clearInterval(times);
way && way();
}
}, 30)
}
利用封装好的运动函数进行小球的运动效果(此处只展示小球运动的代码,不再重复上述的运动函数的代码)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
div {
width: 250px;
height: 250px;
background-color: gray;
border-radius: 50%;
position: absolute;
top: 0;
left: 0;
}
</style>
</head>
<body>
<div id="run"></div>
<button id="btn">开始</button>
<script>
//获取节点
let runObj = document.getElementById('run');
let btnObj = document.getElementById('btn');
//设置运动的目标值,(要运动到哪里)
let target = 1000;
//设置按钮点击事件
btnObj.onclick = function () {
move(runObj, {
left: target
}, function () { // 这里这个function是指元素运动到目标值之后要进行的操作的
函数方法
})
}
/*****此处加入已封装好的运动函数即可运行****/
</script>
</body>
</html>
最后实现一个烟花效果
点击指定区域,会升起一个点(大烟花),然后随机到达一定高度便爆炸生成多个五颜六色(通过随机色实现)的小烟花
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
#container {
width: 80%;
height: 600px;
border: 1px red solid;
position: relative;
margin: 20px auto;
cursor: pointer;
background: black;
}
.fire {
background: red;
position: absolute;
/* 设置bottom时,top获取为最大值,减去鼠标点击位置 */
bottom: 0px;
width: 6px;
height: 6px;
}
.small-fire {
width: 10px;
height: 10px;
position: absolute;
border-radius: 50%;
}
</style>
</head>
<body>
<div id="container">
</div>
<script>
//绑定节点,绑定点击事件
let conObj = document.getElementById('container');
conObj.onclick = function (eve) {
//获取节点位置
let pos = {
cx: eve.offsetX,
cy: eve.offsetY
}
//new构造一个Fire函数
new Fire(conObj, pos);
}
/***大烟花的实现***/
function Fire(conObj, pos) {
//因为在后面也要用到,多次使用,所以先把属性设置成变量
//此时的this指向对象(fire)
this.pos = pos;
this.conObj = conObj;
// console.log(this);
//生成烟花div,且追加class
let bigDiv = document.createElement('div');
//在bigDiv中追加一个类
bigDiv.classList.add('fire');
//设置大烟花样式
bigDiv.style.left = pos.cx + 'px';
bigDiv.style.background = this.getColor();
// console.log(this); //this指向当前节点对象(Fire)
//追加到conObj中
this.conObj.appendChild(bigDiv);
//调用运动函数,从底部运动到鼠标点击的位置
this.move(bigDiv, {
top: this.pos.cy
}, () => {
bigDiv.remove();
this.smallFire()
})
}
/*******小烟花的实现*******/
Fire.prototype.smallFire = function () {
//随机生成小烟花个数
let num = this.rand(20, 50);
//循环,生成div
for (let i = 0; i < num; i++) {
let sFire = document.createElement('div');
//添加class
sFire.className = 'small-fire';
//定义小烟花生成位置为鼠标点击的位置
Object.assign(sFire.style, {
top: this.pos.cy + 'px',
left: this.pos.cx + 'px',
background: this.getColor()
})
//追加到页面中
this.conObj.appendChild(sFire);
//定义小烟花的top和left值,(随机生成的值),让它们四散开来
let top = this.rand(0, this.conObj.offsetHeight -
sFire.offsetHeight);
let left = this.rand(0, this.conObj.offsetWidth -
sFire.offsetWidth);
//调用运动函数
this.move(sFire, {
top,
left }, function () {
sFire.remove();
})
}
}
//封装一个公共的运动函数方法
// let times = '';
Fire.prototype.move = function (ele, target, way) {
// clearInterval(times);
times = setInterval(function () {
var onOff = true;
//遍历运动的方向和目标(即遍历target)
for (let attr in target) { //attr表示运动的属性
//获取元素运动到哪里了的实时值
//想要获取实时值,就要现在外部封装一个获取实时位置的函数方法,然后
再通过这个方法获取实时值
let now = parseInt(this.getPos(ele, attr))
//计算此时速度的值(speed)
let speed = (target[attr] - now) / 10;
//取整数(向上向下取整)
speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);
//设置一个开关的状态(true)用来表示元素运动到终点
if (now == target[attr]) {
onOff = true;
}
//让元素运动
ele.style[attr] = now + speed + 'px';
}
//判断开关的状态,如果到达终点则停止定时器
for (var tip in target) {
if (target[tip] !== parseInt(this.getPos(ele, tip))) {
onOff = false;
break;
}
}
if (onOff) {
clearInterval(times);
way && way();
}
}.bind(this), 30) //使用bind更改this指向
}
//封装一个函数方法来获取元素的实时位置
Fire.prototype.getPos = function (obj, attr) {
//currentStyle和getComputedStyle都是获取元素的全部css样式,分别是兼容写法
if (obj.currentStyle) {
return obj.currentStyle[attr]
} else {
return getComputedStyle(obj)[attr]
}
}
/*****封装一个公共的获取随机数的函数方法*****/ //箭头函数???
Fire.prototype.rand = (min, max) => {
return Math.round(Math.random() * (max - min) + min)
}
/********封装一个公共的设置随机颜色的函数方法*******/
Fire.prototype.getColor = function () {
let c = '#';
for (let i = 0; i < 6; i++) {
c += this.rand(0, 15).toString(16) //
// console.log(this); //this指向当前节点对象(Fire)
}
return c;
}
</script>
</body>
</html>
运行效果感兴趣的可以自行copy运行,有误之处欢迎大家指教交流~~~~3Q