JavaScript学习:缓冲运动的封装

逆战学习
整理一下如何进行缓冲运动的封装

运动的原理

改变运动物体其自身的属性,比如宽高,位置,透明度等等
属性–css属性

要完成这个缓冲运动的封装,首先要利用以下的方法和知识

1.获取任意的css属性值

获取要操纵的元素或者要运动的元素的位置和宽高,透明度;之后才好变化

currentStyle//--兼容IE
getComputedStyle//--该属性是兼容火狐谷歌,不兼容IE
//上面两种有单位,下面四种没有单位
offsetWidth//获取的是盒子最终的宽
offsetHeight//获取的是盒子最终的高
offsetLeft//获取自身左外边框到定位父级的左内边框的距离
offsetTop//获取自身上外边框到定位父级的上内边框的距离
//以上属性只能获取,无法修改 

2.设置物体的css属性值。

元素对象.style.css属性名 = 属性值
元素对象.style.cssText = "css属性代码"

3.定时器–快速的执行

一、简单的运动

有了以上的知识就可以做一个简单的运动;
当然让一个物体位置改变那么它的position就必须是absolute;
比如让一个div盒子水平方向运动;
只需要定时器不断获取它的位置然后加上一个数值赋值给它的位置
css代码

.box {
            width: 100px;
            height: 100px;
            background-color: orange;
            position: absolute;
            left: 0px;
            top: 0;
        }

html代码:

<div class="box"></div>

js代码如下

	const oBox = document.querySelector('.box');
	oBox.onclick = function () {
            //oBox.offsetLeft:获取当前盒子的位置
            //setInterval:间隔定时器(反复执行)
            //通过定时器不断的改变盒子的位置,运动的原理。
            setInterval(() => {
                oBox.style.left = oBox.offsetLeft + 10 + 'px';
            }, 1000 / 60);
        }

后面的代码都是基于这里修改;

二、问题处理和封装

如果运行了上面代码,就会发现有一些问题;
当然运动不可能无休止的进行下去,加入一个目标值。
设置参数并传入函数里面;
这时可以独立一个函数出来,不再是直接写在oBox.onclick这个点击事件里,简单的封装后让oBox调用

问题1:重复点击盒子,定时器会叠加,运动的速度越来越快。
问题2:这是匀速运动,缓冲运动,离目标越远,速度越大。越接近目标,速度越小

解决方式:关闭定时器,设置速度

	 function bufferMove(obj, attr, target) {//obj:元素对象   attr:css属性名。  target:目标属性值
            clearInterval(timer);//解决定时器叠加问题
            timer = setInterval(() => {
                //1.求速度
                //速度>0向上取整,速度<0向下取整。
                speed = (target - parseInt(getStyle(obj, attr))) / 10;//求速度  parseInt:去单位。
                speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);

                //2.判断停止
                if (parseInt(getStyle(obj, attr)) === target) {//停止
                    clearInterval(timer);
                } else {//继续运动
                    oBox.style[attr] = parseInt(getStyle(obj, attr)) + speed + 'px';
                }
            }, 1000 / 60);
        }
        oBox.onclick = function () {
            bufferMove(oBox, 'width', 1000)
        }

上面的函数里面还有一个方法叫getStyle,是获取任意css属性值的一个兼容写法
代码如下:

 function getStyle(obj, attr) {//obj:元素对象,attr:css属性名
            if (window.getComputedStyle) {//条件用属性做,不存在就是undefined,标准
                return window.getComputedStyle(obj)[attr];
            } else {//非标准
                return obj.currentStyle[attr];//100px
            }
        }

到这里已经可以解决上下左右运动的问题了;但是如果我想改变其他的属性而不只是位置呢,我想改变透明度又该如何解决

问题3:任意属性的改变 --getStyle函数解决
问题4:任意属性的改变 --改变透明度—通过判断属性解决

问题三已经通过getStyle函数解决了,但是只是取到了元素和属性,那么透明度的改变就需要增加条件来判断取出的属性是不是透明度;
1.在定时器函数里增加一个当前值currentValue初始值为null占位置;
2.然后判断属性是否为opacity分别赋值给当前值;
3.opacity值区间为0-1;扩大100倍数方便与位置的数值差不多便于计算速度;
4.判断停止时注意将 opacity 值缩小100倍再赋给元素;
代码如下:

var currentValue = null;//1
    if (attr === 'opacity') {//opacity透明度  2
         currentValue = Math.round(getStyle(obj, attr) * 100); //  3
     } else {//其他css属性
         currentValue = parseInt(getStyle(obj, attr));
     }

	speed = (target - currentValue) / 10;//求速度  parseInt:去单位。
    speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);

if (currentValue === target) {//停止
	  clearInterval(timer);
	} else {//继续运动
	   if (attr === 'opacity') {
	       obj.style.opacity = (currentValue + speed) / 100;//缩小100倍  4
	       obj.style.filter = 'alpha(opacity=' + (currentValue + speed) + ')';//IE
	   } else {
	       obj.style[attr] = currentValue + speed + 'px';
	   }
	}

做到这里单个物体的缓冲运动已经差不多做好了;
但如果你测多个物体的运动时就又出现bug,比较混乱;
而且我想要物体的宽度变了之后透明度或者高度也能运动起来;

问题5:多物体运动–多物体共用一个定时器出现问题。
问题6:物体进行链式运动(上一次运动结束,才开启下一次运动)

解决方法:
1.给定时器的返回值设置为当前 对象.值 — obj.timer
这样每一个物体的定时器都是不同的
2.链式运动,可以在函数调用时再调用自身
3.再给原函数增加参数fn 这样原函数参数为(obj,attr, target,fn)
4.判断fn是否执行,若不存在或传入参数不是函数就不执行。可以用逻辑运算符做判断条件 — fn && typeof fn === ‘function’ && fn();
代码如下:
给bufferMove函数下的定时器设置返回值

	obj.timer = setInterval(function () {
	}

然后给判断停止时里面的条件加一句执行回调函数的代码

if (currentValue === target) {//运动停止
 clearInterval(obj.timer);
  fn && typeof fn === 'function' && fn();//执行回调函数,如果fn存在,执行fn
   } 

现在还有些问题,当前只能够每次改变一个属性,如果想要多个目标和属性变化,则还需要优化。

问题7:多属性同时运动

解决方法:
1.把属性装入一个对象里面,for…in遍历取出,设这个对象名为 json
2.就是把定时器里面的代码放入for…in这个遍历中

function bufferMove(obj, json, fn) {  
            let speed = 0;
            clearInterval(obj.timer);//将定时器的返回值给obj元素的属性。
            obj.timer = setInterval(function () {
                for (var attr in json) {//之前定时器里面的代码
                //attr和之前表示的意义相同,目标值target变为json[attr]就可以

				}
				}, 1000 / 60);
        }

到了此时,运行代码,还是存在问题,某些属性没有达到目标值运动就停止了。
于是出现了新的问题问题,只要有一个到了目标点,运动停止了
当然这是不行的,需要所有的物体都到了目标点,才停止。

问题8:如果有一个到了目标点,运动停止了。

解决方法:
1.把定时器停止和回调函数执行的代码块提出遍历的代码块
2.假设一个标记设分为flag;初始值flag= true;
3.改变判断停止的条件,只要有一个没有到目标点就继续运动
4.给判断停止的条件末尾加一句 flag = false;
5.通过判断flag的布尔值来让定时器停止和回调函数执行;
代码:

function bufferMove(obj, json, fn) {
            let speed = 0;
            clearInterval(obj.timer);
            obj.timer = setInterval(function () {
                var flag = true; //假设标记,代表运动结束
                for (var attr in json) {//attr:css属性名
                    var currentValue = null;
                    if (attr === 'opacity') {
                        currentValue = Math.round(getStyle(obj, attr) * 100);  
                    } else {
                        currentValue = parseInt(getStyle(obj, attr));
                    } 
                    speed = (json[attr] - currentValue) / 10;
                    speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);
                    //3.判断停止
                    if (currentValue !== json[attr]) {//没到目标点,继续运动
                        if (attr === 'opacity') {
                            obj.style.opacity = (currentValue + speed) / 100;
                            obj.style.filter = 'alpha(opacity=' + (currentValue + speed) + ')';//IE
                        } else {
                            obj.style[attr] = currentValue + speed + 'px';
                        }
                        flag = false;//flag为flase表示运动还未停止
                    }
                }
                if (flag) {
                    clearInterval(obj.timer);
                    fn && typeof fn === 'function' && fn();//执行回调函数,如果fn存在,执行fn
                }

            }, 1000 / 60);
        }

最后,这个缓冲运动的封装就完成了,适合单物体,多物体的位置,宽高,透明度的运动。

三、总结:

这个缓冲运动的封装的参数为(obj,json,fn);
obj:所要操纵运动的元素;
json:运动的属性和目标值—例如

       {width:200,//width表示属性,后面数值表示目标值(运动的终点)
		height:300
 		}

fn:是否进行链式运动的函数

最终代码就是最后封装的那部分加上getStyle函数,可以把他们单独写入一个js文件,哪个时候需要就引入。

微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值