转自个人博客三省吾身丶丶
本来是JS动画效果,然则我会过甚再看的时刻,发明太大略了,因而从新写了一篇。
喜好别只珍藏啊,点个引荐,大兄弟^ ^!
活动框架的完成思绪
活动,实在就是在一段时候内转变
left
、right
、width
、height
、opactiy
的值,抵达目标地以后住手。
如今依据以下步骤来举行我们的活动框架的封装:
匀速活动。
缓冲活动。
多物体活动。
恣意值变化。
链式活动。
同时活动。
(一)匀速活动
速率动画
活动基本
思索:怎样让div
动起来?
以下:
设置元素为相对定位,只要相对定位后,
left
,top
等值才见效。定时器的运用(动态转变值),这里运用
setInterval()
每隔指定的时候实行代码。计时器
setInterval(函数,交互时候(毫秒))
:在实行时,从载入页面后每隔指定的时候实行代码。作废计时器
clearInterval(函数)
要领可作废由setInterval()
设置的交互时候。
猎取当前的位置,大小等等。
offsetLeft
(当前元素相对父元素位置)。速率–物体活动的快慢
定时器间隔时候
转变值的大小
依据上面的信息我们就能够最先封装活动框架建立一个变化的div
了。
/**
* 活动框架-1-动起来
* @param {HTMLElement} element 举行活动的节点
*/
var timer = null;
function startMove(element) {
timer = setInterval(function () {//定时器
element.style.left = element.offsetLeft + 5 + "px";
}, 30);
}
你没看错,就是那末简朴。然则等等, what? 怎样不会停?WTF?
那是因为我们没有活动停止前提。好再照样比较简朴。直接在定时器内部,推断抵达目标值,消灭定时器就行拉!
/**
* 活动框架-2-活动停止
* @param {HTMLElement} element 举行活动的节点
* @param {number} iTarget 活动停止前提。
*/
var timer = null;
function startMove(element, iTarget) {
timer = setInterval(function () {
element.style.left = element.offsetLeft + 5 + "px";
if (element.offsetLeft === iTarget) {//住手前提
clearInterval(timer);
}
}, 30);
}
就如许是不是是就完成了呢?已ok了呢?
no。另有一些Bug须要处置惩罚。
活动中的Bug
速率取到某些值会没法住手
抵达位置后再点击还会活动
反复点击速率加速
速率没法变动
处理BUG
速率取到某些值会没法住手(这个Bug稍后处理,在进化历程当中天然处理)
把活动和住手离隔(if/else)
在最先活动时,封闭已有定时器
把速率用变量保留
/**
* 活动框架-3-处理Bug
*/
var timer = null;
function startMove(element, iTarget) {
clearInterval(timer);//在最先活动时,封闭已有定时器
timer = setInterval(function () {
var iSpeed = 5;//把速率用变量保留
//把活动和住手离隔(if/else)
if (element.offsetLeft === iTarget) {//完毕活动
clearInterval(timer);
} else {
element.style.left = element.offsetLeft + iSpeed + "px";
}
}, 30);
}
如许一个简朴的活动框架就完成了。然则,再等等。只能向右走?别急,我们不是定义了把速率变成为了变量吗?只须要对它举行一些处置惩罚就行啦!var iSpeed = 5;
–>
//推断间隔目标位置,到达自动变化速率正负
var iSpeed = 0;
if (element.offsetLeft < iTarget) {
iSpeed = 5;
} else {
iSpeed = -5;
}
透明度动画
用变量
alpha
贮存当前透明度。把上面的
element.offsetLeft
改成变量alpha
。活动和住手前提部份举行变动。以下:
//透明度浏览器兼容完成
if (alpha === iTarget) {
clearInterval(time);
} else {
alpha += speed;
element.style.filter = 'alpha(opacity:' + alpha + ')'; //兼容IE
element.style.opacity = alpha / 100;//规范
}
(二)缓冲动画
思索:怎样才是缓冲动画?
应该有以下几点:
逐步变慢,末了住手
间隔越远速率越大
速率由间隔决议
速率=(目标值-当前值)/缩放系数
Bug :速率取整(运用Math要领),不然会闪
向上取整。
Math.ceil(iSpeed)
向下取整。
Math.floor(iSpeed)
照样对速率作文章:
/**
* 活动框架-4-缓冲动画
*/
function startMove(element, iTarget) {
clearInterval(timer);
timer = setInterval(function () {
//因为速率要动态转变,所以必需放在定时器中
var iSpeed = (iTarget - element.offsetLeft) / 10; //(目标值-当前值)/缩放系数=速率
iSpeed = iSpeed > 0 ? Math.ceil(iSpeed) : Math.floor(iSpeed); //速率取整
if (element.offsetLeft === iTarget) {//完毕活动
clearInterval(timer);
} else {
element.style.left = element.offsetLeft + iSpeed + "px";
}
}, 30);
}
做到这里,(速率取到某些值会没法住手)这个Bug就自动处理啦!
例子:缓冲菜单
追随页面转动的缓冲侧边栏
在线演示:codepen
潜伏题目目标值不是整数时
(三)多物体活动
思索:怎样完成多物体活动?
单定时器,存在题目。每一个div一个定时器
定时器作为对象的属性
直接运用
element.timer
把定时器变成对象上的一个属性。
参数的通报:物体/目标值
比较简朴把上面框架的举行以下变动:timer
–>element.timer
就如许就行啦!
(四)恣意值变化
咳咳。我们来给div加个1px的边框。boder :1px solid #000
然后来尝尝下面的代码
setInterval(function () {
oDiv.style.width = oDiv.offsetWidth - 1 + "px";
}, 30)
嗯,奇异的事变发生了!what?我设置的不是宽度在减吗?怎样尼玛增加了! 不对啊,大兄弟。
终究那里出了题目呢?
一同找找材料,看看文档,本来offset
这一系列的属性都邑存在,被其他属性滋扰的题目。
好吧,既然不能用,那末我们就顺便把恣意值变化给做了吧。
第一步:猎取现实款式
运用offsetLeft..等猎取款式时, 若设置了边框, padding, 等能够转变元素宽度高度的属性时会涌现BUG..
经由历程查找发明
element.currentStyle(attr)
能够猎取计算过以后的属性。然则因为兼容性的题目,需封装getStyle函数。(万恶的IE)
固然合营CSS的
box-sizing
属性设为border-box
能够到达一样的效果 ? (自认为,未考证)。
/**
* 猎取现实款式函数
* @param {HTMLElement} element 须要寻觅的款式的html节点
* @param {String]} attr 在对象中寻觅的款式属性
* @returns {String} 猎取到的属性
*/
function getStyle(element, attr) {
//IE写法
if (element.currentStyle) {
return element.currentStyle[attr];
//规范
} else {
return getComputedStyle(element, false)[attr];
}
}
第二步:革新原函数
增加参数,
attr
示意须要转变的属性值。变动
element.offsetLeft
为getStyle(element, attr)
。须要注重的是:
getStyle(element, attr)
不能直接运用,因为它猎取到的字符串,例:10px
。变量
iCurrent
运用parseInt()
,将款式转成数字。
element.style.left
为element.style[attr]
。
/**
* 活动框架-4-恣意值变化
* @param {HTMLElement} element 活动对象
* @param {string} attr 须要转变的属性。
* @param {number} iTarget 目标值
*/
function startMove(element, attr, iTarget) {
clearInterval(element.timer);
element.timer = setInterval(function () {
//因为速率要动态转变,所以必需放在定时器中
var iCurrent=0;
iCurrent = parseInt(getStyle(element, attr));//现实款式大小
var iSpeed = (iTarget - iCurrent) / 10; //(目标值-当前值)/缩放系数=速率
iSpeed = iSpeed > 0 ? Math.ceil(iSpeed) : Math.floor(iSpeed); //速率取整
if (iCurrent === iTarget) {//完毕活动
clearInterval(element.timer);
} else {
element.style[attr] = iCurrent + iSpeed + "px";
}
}, 30);
}
试一试,如许是不是是就能够了呢?
还记得上面我们写的透明度变化吗? 再尝尝
果真照样不可, (空话,你见过透明度有”px”单元的么? – –白眼
)
第三步:透明度兼容处置惩罚
思索:须要对那些属性举行修正?
推断
attr
是不是是透明度属性opacity
。关于速率举行处置惩罚。
为透明度时,因为猎取到的透明度会是小数,所以须要 * 100
而且因为计算机贮存浮点数的题目,还须要将小数,举行四舍五入为整数。运用:
Math.round(parseFloat(getStyle(element, attr)) * 100)
。不然,继承运用默许的速率。
对效果输出部份举行变动。
推断是透明度属性,运用透明度要领
不然,运用运用默许的输出花样。
/**
* 活动框架-5-兼容透明度
* @param {HTMLElement} element 活动对象
* @param {string} attr 须要转变的属性。
* @param {number} iTarget 目标值
*/
function startMove(element, attr, iTarget) {
clearInterval(element.timer);
element.timer = setInterval(function () {
//因为速率要动态转变,所以必需放在定时器中
var iCurrent = 0;
if (attr === "opacity") { //为透明度时实行。
iCurrent = Math.round(parseFloat(getStyle(element, attr)) * 100);
} else { //默许状况
iCurrent = parseInt(getStyle(element, attr)); //现实款式大小
}
var iSpeed = (iTarget - iCurrent) / 10; //(目标值-当前值)/缩放系数=速率
iSpeed = iSpeed > 0 ? Math.ceil(iSpeed) : Math.floor(iSpeed); //速率取整
if (iCurrent === iTarget) {//完毕活动
clearInterval(element.timer);
} else {
if (attr === "opacity") { //为透明度时,实行
element.style.filter = "alpha(opacity:" + (iCurrent + iSpeed) + ")"; //IE
element.style.opacity = (iCurrent + iSpeed) / 100; //规范
} else { //默许
element.style[attr] = iCurrent + iSpeed + "px";
}
}
}, 30);
}
到这里,这个活动框架就基本上完成了。然则,我们是寻求圆满的不是吗?
继承进化!
(五)链式动画
链式动画:望文生义,就是在该次活动住手时,最先下一次活动。
怎样完成呢?
运用回调函数:活动住手时,实行函数
增加
func
形参(回调函数)。在当前属性抵达目标地时
iCurrent === iTarget
,推断是不是有回调函数存在,有则实行。
if (iCurrent === iTarget) {//完毕活动
clearInterval(element.timer);
if (func) {
func();//回调函数
}
}
good,链式动画完成!间隔圆满还差一步!
(六)同时活动
思索:怎样完成同时活动?
运用JSON通报多个值
运用
for in
轮回,遍历属性,与值。定时器题目!(活动提早住手)
在轮回外设置变量,假定一切的值都抵达了目标值为true
在轮回中检测是不是抵达目标值,若没有值未到则为false
在轮回完毕后,检测是不是悉数到达目标值.是则消灭定时器
完成:
删除
attr
与iTarget
两个形参,改成json
在函数最先时,设置一个标记
var flag = true; //假定一切活动抵达尽头.
在定时器内运用
for in
,遍历属性与目标,改写本来的attr
与iTarget
,为json的属性与值修正活动停止前提,只要每一项的现实属性值
iCurrent
,即是目标值json[attr]
时,flag
才为true
。消灭定时器,推断是不是回调。不然,继承实行代码,直到一切属性值即是目标值。
圆满活动框架
/**
* 猎取现实款式函数
* @param {HTMLElement} element 须要寻觅的款式的html节点
* @param {String]} attr 在对象中寻觅的款式属性
* @returns {String} 猎取到的属性
*/
function getStyle(element, attr) {
//IE写法
if (element.currentStyle) {
return element.currentStyle[attr];
//规范
} else {
return getComputedStyle(element, false)[attr];
}
}
/**
* 圆满活动框架
* @param {HTMLElement} element 活动对象
* @param {JSON} json 属性:目标值
* @property {String} attr 属性值
* @config {Number} target 目标值
* @param {function} func 可选,回调函数,链式动画。
*/
function startMove(element, json, func) {
var flag = true; //假定一切活动抵达尽头.
clearInterval(element.timer);
element.timer = setInterval(function () {
for (var attr in json) {
//1.取当前的属性值。
var iCurrent = 0;
if (attr === "opacity") { //为透明度时实行。
iCurrent = Math.round(parseFloat(getStyle(element, attr)) * 100);
} else { //默许状况
iCurrent = parseInt(getStyle(element, attr)); //现实款式大小
}
//2.算活动速率,动画缓冲效果
var iSpeed = (json[attr] - iCurrent) / 10; //(目标值-当前值)/缩放系数=速率
iSpeed = iSpeed > 0 ? Math.ceil(iSpeed) : Math.floor(iSpeed); //速率取整
//3.未抵达目标值时,实行代码
if (iCurrent != json[attr]) {
flag = false; //停止前提
if (attr === "opacity") { //为透明度时,实行
element.style.filter = "alpha(opacity:" + (iCurrent + iSpeed) + ")"; //IE
element.style.opacity = (iCurrent + iSpeed) / 100; //规范
} else { //默许
element.style[attr] = iCurrent + iSpeed + "px";
}
} else {
flag = true;
}
//4. 活动停止,是不是回调
if (flag) {
clearInterval(element.timer);
if (func) {
func();
}
}
}
}, 30);
}
活动框架总结
活动框架演化历程
框架 | 变化 |
---|---|
startMove(element) | 活动 |
startMove(element,iTarget) | 匀速–>缓冲–>多物体 |
startMove(element,attr,iTargrt) | 恣意值 |
startMove(element,attr,iTargrt,func) | 链式活动 |
startMove(element,json,func) | 多值(同时)–>圆满活动框架 |