运动函数
// css 样式
<style>
*{
margin: 0;
padding: 0;
}
div{
width: 100px;
height: 100px;
background-color: pink;
position: absolute;
top: 0;
left: 0;
}
</style>
// html
<div class="box"></div>
js 实现
- 运动函数实现 1
- 需求: 点击这个 div 让向右移动 100px
// 获取元素
const oBox = document.querySelector('.box'); // 获取box
// 给box添加点击事件
oBox.onclick = function(){
// console.log(this); // 查看oBox的this指向 => <div class="box"></div>
this.style.left = 100 + 'px'; // 点击oBox 使其运动100px
let count = 0; // 定义计数器
// 定义一个变量 把oBox 的this指向赋值给变量
const that = this;
// 定义计时器
const time = setInterval(function(){
// console.log(this); // 查看 this 的指向 => window
//设置步长 => 一次运动的距离
count += 5;
// 当 计数器等于 目标距离时/ 原始距离等于目标距离时 清楚计时器
// 运动距离等于最后的开始距离
that.style.left = count + 'px'; // 左边距离
// 当开始距离等于 目标距离时 清除定时器 不再运动 => 即移动
if(count == 100){
clearInterval(time); // 清除计时器
}
},50)
console.log(that.style.left); // 查看运动后的距离 => 打印结果 100px
}
- 运动函数实现 2
- 问题: 每次运动都从 0 的位置开始移动
- 原因: 运动函数的 初始值, 是从 0 开始的
- 解决: 获取到元素本身值, 然后再次基础上移动
// 获取元素
const oBox = document.querySelector('.box'); // 获取box
// 运动函数封装
/* ele: 移动那个元素
type: 修改那个属性
target: 移动的目标距离*/
function move(ele,type,target){
// ele.style.left = 100 + 'px'; // 点击oBox 使其运动100px
// console.log(window.getComputedStyle(ele)[type]); // 获取元素本身的值 作为运动起点
let count = parseInt(window.getComputedStyle(ele)[type]); // 运动起点
// 定义一个变量 把oBox 的this指向赋值给变量
// const that = this;
// 定义计时器
const time = setInterval(function(){
count += 5;
// 当 计数器等于 目标距离时/ 原始距离等于目标距离时 清楚计时器
// 运动距离等于最后的开始距离
ele.style[type] = count + 'px'; // 左边距离
// 当开始距离等于目标距离时 清除计时器 停止运动 => 即移动
if(count == target){
clearInterval(time); // 清除计时器
}
},50)
}
// 给box添加点击事件
oBox.onclick = function(){
// 调用运动函数
move(this,'left',100); // this(元素本身) '属性' '目标距离'
}
- 运动函数实现 3
- 问题: 从 200 移动到 501 时, 不会停止
- 原因: 移动距离, 不是 每次移动的整倍数
- 现在从 200开始移动, 移动到501 移动距离 301
- 301 不是每次运动的整倍数
- 解决: 1. 每次移动距离修改为 1
- 弊端, 运动速度固定了, 如果运动的路程不同, 就会导致时间不同
-
- 每次移动总路程的 1/10 (匀速)
- 现在从 200开始移动, 移动到501 移动距离 301
- 每次都移动 30.1
- 现在从 300开始移动, 移动501 移动距离 201
- 每次都移动 20.1
-
- 每次移动剩余路程的 1/10 (降速)
- 3.1 现在 从 0 开始移动, 移动到 100 移动距离 100
- 现在移动 100 / 10 === 10
- 3.2 现在 从 10 开始移动, 移动到 100 移动距离 90
- 现在移动 90 / 10 === 9
// 获取元素
const oBox = document.querySelector('.box'); // 获取box
// 运动函数封装
/* ele: 移动那个元素
type: 修改那个属性
target: 移动的目标距离*/
function move(ele,type,target){
// ele.style.left = 100 + 'px'; // 点击oBox 使其运动100px
// 定义一个变量 把oBox 的this指向赋值给变量
// const that = this;
// 定义计时器
const time = setInterval(function(){
// console.log(window.getComputedStyle(ele)[type]); // 获取元素本身的值 作为运动起点
let count = parseInt(window.getComputedStyle(ele)[type]); // 运动起点
// count += 1;
// count += 1; => count += 5 运动距离200-501 => 到501时 不会停止 步长为5 => 修改:count += 1
// 运动距离 = 目标距离 - 起始距离
let def = (target - count) / 10;
// 当 计数器等于 目标距离时/ 原始距离等于目标距离时 清楚计时器
// 当开始距离等于目标距离时 清除计时器 停止运动 => 即移动
if(count === target){
clearInterval(time); // 清除计时器
}else{
// 运动距离 = 起始距离 + 运动距离
ele.style[type] = count + def + 'px'; // 左边距离
}
},20)
}
/* html
// 给box添加点击事件
oBox.onclick = function(){
// 调用运动函数
move(this,'left',501); // this(元素本身) '属性' '目标距离'
move(this,'top',200)
}
*/
- 运动函数实现 4
- 问题: 没有移动到指定的距离
- 原因: 当前在的位置 91px 需要移动到 100px, 下一次移动距离 (100 - 91) / 10 === 0.9
- 当前移动的距离 应该是 91 + 0.9 + 'px' === 91.9px
- 但是浏览器可识别的最小移动距离 为 1px, 所以赋值移动到 91.9px 时, 实际位置 还是91px
- 解决: 将移动的距离 向上取整
- 新问题:
- 当前在的位置 9px 需要移动 0px, 下一次移动距离 (0 - 9) / 10 === -0.9
- 然后我们将移动值, 向上取整 -0.9 => 0
- 解决: 当移动的值 大于0的时候, 向上取整, 否则 向下取整
function move(ele, type, target) {
const timer = setInterval(function () {
// 1. 获取当前的位置
let count = parseInt(window.getComputedStyle(ele)[type])
// 2. 计算要移动的距离 (目标 - 当前的值) / 10
let des = (target - count)
// 3. 判断是否需要继续移动
if (target === count) {
// 3.1 此时说明移动到了, 可以结束定时器
clearInterval(timer)
} else {
// 3.2 此时说明还没有移动到, 需要继续移动
ele.style[type] = count + des + 'px'
}
}, 20)
}
- 运动函数实现 5
- 问题: 透明没有调整
- 原因: 透明度没有单位
- 解决: 在赋值的时候, 判断如果时 透明度, 那么就别带单位
- 新问题: 没有运动过程
- 原因: 因为做了取整之后, 得到的值, 只会是 -1或者1
- 解决: 想个办法, 将值放大
// 0. 封装一个运动函数
function move(ele, type, target) {
if (type == 'opacity') {
target *= 100
}
const timer = setInterval(function () {
// 1. 获取当前的位置
let count
if (type == 'opacity') {
count = window.getComputedStyle(ele)[type] * 100
} else {
count = parseInt(window.getComputedStyle(ele)[type])
}
// 2. 计算要移动的距离 (目标 - 当前的值) / 10
let des = (target - count) / 10
// 大于0 向上取整, 小于0 向下取整
des = des > 0 ? Math.ceil(des) : Math.floor(des)
// 3. 判断是否需要继续移动
if (target === count) {
// 3.1 此时说明移动到了, 可以结束定时器
clearInterval(timer)
} else {
// 3.2 此时说明还没有移动到, 需要继续移动
if (type == 'opacity') {
ele.style[type] = (count + des) / 100
} else {
ele.style[type] = count + des + 'px'
}
}
}, 50)
}
- 运动函数实现 6
- 问题: 我们现在想在运动函数结束之后在某些事, 但是目前没法做到
- 原因: 运动函数是 异步的, 所以会先执行同步代码
- 解决: 在运动函数开始的时候, 给他一个 "锦囊" 然后告诉运动函数
- 在你运动完了的时候, 才能打开 "锦囊"
- 回调函数 (本质上就是一个函数)
- 将函数A以实参的形式传递给函数B, 然后函数B在函数内部以形参的方式调用函数A
- 此时函数A可以称为函数B的回调函数
- 回调函数一般用异步代码的封装
// 获取元素
const oBox = document.querySelector('.box'); // 获取box
// 准备变量 用于计数作用
let num = 0;
function move(ele,obj,fun = () => {}){ // ele => 运动元素 obj => 传入参数对象
// console.log(obj); // => 打印结果 对象
// 通过循环拿到对象每一个键和值
for(let key in obj){
// console.log(obj[key]); // 拿到值 => 目标距离
// console.log(key); // 拿到 相应的type值
let type = key;
let target = obj[key];
if(type == 'opacity'){
target *= 100; // 初始值 放大100 => 目标距离放大100 => 保证放大后 计算没有改变
}
num++; // 计时器开始前让计数器自增 用于记录计时器是否已经结束
// 定义计时器
const time = setInterval(function(){
// console.log(window.getComputedStyle(ele)[type]); // 获取元素本身的值 作为运动起点
let count;
if(type == 'opacity'){ // 判断是否为透明度 为透明度将值放大100倍
count = window.getComputedStyle(ele)[type] * 100; // 不会带单位 所以去掉parseInt
}else{
count = parseInt(window.getComputedStyle(ele)[type]); // 运动起点
}
// count += 1; => count += 5 运动距离200-501 => 到501时 不会停止 步长为5 => 修改:count += 1
// 运动距离 = 目标距离 - 起始距离
let def = (target - count) / 10;
// 当 计数器等于 目标距离时/ 原始距离等于目标距离时 清楚计时器
// 解决91-100 一直停留在91.9
// def = Math.ceil(def);
// 解决0-9 无法移动到目标位置
def = def > 0 ? Math.ceil(def) : Math.floor(def);
// 当开始距离等于目标距离时 清除计时器 停止运动 => 即移动
if(count === target){
num--;
clearInterval(time); // 清除计时器
if(num == 0){
console.log('计时器结束');
fun(); // 计时器结束调用函数 执行结束后的操作
}
}else{
if(type == 'opacity'){
// 初始值放大100 倍 变化值缩小100倍
ele.style[type] = (count + def) / 100; // 判断传入参数里有无透明度 如果有 就不带px单位
}else{ // 不是透明度 就带px单位
ele.style[type] = count + def + 'px'; // 左边距离
}
// 运动距离 = 起始距离 + 运动距离
}
// console.log(ele.style[type]); // 一直停留在91.9 无法到达 目标位置
},20)
}
}