首先创建一个方格
<!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>
.box {
width: 100px;
height: 100px;
position: absolute;
left: 0px;
top: 0px;
background: red;
}
</style>
</head>
<body>
<div class="box"></div>
</body>
一、回调
<script>
//四个参数分别是事件、目标位置、方向、回调函数
function move(ele, target, dir, cb) {
//获取最开始的left值,并parseInt()取整
let startLeft = parseInt(getComputedStyle(ele, null)[dir]);
// console.log(startLeft)
//设置一个速度,通过初始值和目标值的差值正负关系来决定运动方向
let speed = (target - startLeft) > 0 ? 1 : -1;
setTimeout(() => {
//给初始值加上速度
startLeft += speed;
if (startLeft === target) {
//当和目标值相同,运动完成
// 可以打印console.log("运动完成");
//通过回调函数来执行异步函数
cb && cb();
} else {
//给事件的left赋值
ele.style[dir] = startLeft + "px";
//加上循环,运动完成后不会再调用move
move(ele, target, dir, cb);
}
}, 10);
}
// requestAnimationFrame性能比setTimeout性能更好
//获取事件
let ele = document.querySelector(".box");
//传入一个方向,"left"和"top"能控制运动方向
//下面两个是同步执行的,不能先右移动再下移动,而是右下斜着移动
// move(ele, 300,"left");
// move(ele, 300,"top");
// 通过回调解决异步;回调地狱(函数嵌套关系太复杂,后期难以维护)
move(ele, 300, "left", function () {
move(ele, 300, "top", function () {
move(ele, 0, "left", function () {
move(ele, 0, "top", function () {
console.log("运动完成");
})
})
})
})
</script>
二、自定义事件(观察者模式)
<script>
//首先自定义一个事件
let eventObj = new EventTarget();
//设置一个变量,为了后面区分事件名
let num = 1;
//不需要回调了,删除cb
function move(ele, target, dir) {
let startLeft = parseInt(getComputedStyle(ele, null)[dir]);
// console.log(startLeft)
// let speed =(target-startLeft)/ Math.abs( target-startLeft ) ; 这是通过绝对值来确定+-1
let speed = (target - startLeft) > 0 ? 1 : -1;
setTimeout(() => {
startLeft += speed;
if (startLeft === target) {
// console.log("运动完成");
// cb && cb(); 不用上个方法的回调了
//通过下面方法触发自定义事件,myevent+num是事件名称,num++设置不同的事件名
eventObj.dispatchEvent(new CustomEvent("myevent"+num));
num++;
} else {
ele.style[dir] = startLeft + "px";
move(ele, target, dir);
}
}, 10);
}
let ele = document.querySelector(".box");
//调取move函数
move(ele, 300, "left");
//绑定事件
eventObj.addEventListener("myevent1",function(){
console.log("事件触发,运动完成myevent1");
move(ele, 300, "top");
});
eventObj.addEventListener("myevent2",function(){
console.log("事件触发,运动完成myevent2");
move(ele, 0, "left")
});
eventObj.addEventListener("myevent3",function(){
console.log("事件触发,运动完成myevent3");
move(ele, 0, "top")
});
eventObj.addEventListener("myevent4",function(){
console.log("事件触发,运动完成myevent4");
});
//优点:没有嵌套 缺点:实现起来麻烦,代码冗余
</script>
三、Promise对象
<script>
function move(ele, target, dir) {
//返还一个promise对象
return new Promise(resolve => {
//用一个函数把之前的move封装起来,防止返还很多promise对象
function fn() {
let startLeft = parseInt(getComputedStyle(ele, null)[dir]);
// console.log(startLeft)
// let speed =(target-startLeft)/ Math.abs( target-startLeft ) ;
let speed = (target - startLeft) > 0 ? 1 : -1;
setTimeout(() => {
startLeft += speed;
if (startLeft === target) {
// console.log("运动完成");
// cb && cb();
//返还一个完成提示
resolve("运动完成");
} else {
ele.style[dir] = startLeft + "px";
//不再使用回调
fn();
}
}, 10);
}
//调用这个内部函数
fn();
})
}
let ele = document.querySelector(".box");
// 通过一层层的then方法实现链式操作
move(ele, 300, "left").then(res=>{
//console.log(res);
//执行完第一次,返回一个函数,继续执行相同的操作,以此类推,直到所有操作完成
return move(ele, 300, "top");
}).then(res=>{
// console.log(res);
return move(ele, 0, "left");
}).then(res=>{
return move(ele, 0, "top");
}).then(res=>{
console.log("所有运动完毕");
})
</script>
四、Async函数
<script>
function move(ele, target, dir) {
//返还一个promise对象
return new Promise(resolve => {
//用一个函数把之前的move封装起来,防止返还很多promise对象
function fn() {
let startLeft = parseInt(getComputedStyle(ele, null)[dir]);
// console.log(startLeft)
// let speed =(target-startLeft)/ Math.abs( target-startLeft ) ;
let speed = (target - startLeft) > 0 ? 1 : -1;
setTimeout(() => {
startLeft += speed;
if (startLeft === target) {
// console.log("运动完成");
// cb && cb();
//返还一个完成提示
resolve("运动完成");
} else {
ele.style[dir] = startLeft + "px";
//不再使用回调
fn();
}
}, 10);
}
//调用这个内部函数
fn();
})
}
let ele = document.querySelector(".box");
//上面这部分和promise方法一样
//先声明一个async函数
async function asyncFn(){
try{
//使用await 操作符依次执行操作
await move(ele, 300, "left");
await move(ele, 300, "top");
await move(ele, 0, "left");
await move(ele, 0, "top");
}catch(e){
console.log(e);
}
//可以用catch捕获失败的操作
}
//最后调用这个函数
asyncFn();
</script>