1.匀速直线运动
原理详解
var oDiv = document.getElementsByTagName('div')[0];
var oBtn = document.getElementsByTd('btn');
var timer = null;
oBtn.onclick = function(){
// 每次执行先clear一下,保证每次触发的事件不会叠加生效
clearInterval(timer);
// 判断当前div是在目标300px处的左侧还是右侧,若在左侧,移动7px,若在右侧,移动 -7px
var iSpeed = 300 - oDiv.offsetLeft > 0 ? 7 : - 7;
// 延时30ms执行以下函数,在其定位位置每次右移4px
timer = setInterval(function (){
// 让方块运动到300px处停止,判断离300px相差是否小于4px
// 使用 Math.abs() 取绝对值,不考虑正负号
if(Math.abs(300 - oDiv.offsetLeft) < Math.abs(iSpeed)){
clearInterval(timer);
oDiv.style.left = '300px';
}else{
// 为div位置赋值,每次增加7px
oDiv.style.left = oDiv.offsetLeft + iSpeed + 'px';
}
}, 30);
实现封装
// dom:让谁移动(oDiv) target:移动到哪(300)
function startMove(dom, target){
clearInterval(timer);
var iSpeed = target - oDiv.offsetLeft > 0 ? 7 : - 7;
timer = setInterval(function (){
if(Math.abs(target - dom.offsetLeft) < Math.abs(iSpeed)){
clearInterval(timer);
dom.style.left = target + 'px';
}else{
dom.style.left = dom.offsetLeft + iSpeed + 'px';
}
}, 30);
}
2.缓冲运动
物体的速度,距离目标点越近,就越慢,当到达目标点时,停止
实现封装
function startMove(dom, target){
clearInterval(timer);
var iSpeed = null;
timer = setInterval(function(){
// 移动速度为:目标位置-初始位置 / 7(可改,调速)
iSpeed = (target - oDiv.offsetLeft) / 7;
// 判断速度是正数或负数,正数向上取整,负数向下取整
iSpeed = iSpeed > 0 ? Math.ceil(iSpeed) : Math.floor(iSpeed);
if(oDiv.offsetLeft == target) {
clearInterval(timer);
}else{
oDiv.style.left = oDiv.offsetLeft + iSpeed + 'px';
}
}, 30);
}
应用demo
页面侧面伸缩栏,鼠标移上去后,菜单弹出来,鼠标移走,菜单缩回去
<style>
/* 设置样式,div样式为400px,初始状态在-400px,处于隐藏状态 */
.wrapper {
width: 400px;
height: 80px;
background: orange;
position: absolute;
left: -400px;
top: 200px;
}
/* span样式大小为50px,在div右侧占50px,在页面中显示 */
.wrapper span {
width: 50px;
height: 80px;
background: red;
position: absolute;
right: -50px;
top: 0px;
}
</style>
<div class="wrapper">
<span></span>
</div>
<script>
var timer = null;
// 将div选中
var oDiv = document.getElementsByClassName('wrapper')[0];
// 鼠标移入事件,鼠标移入后,将div移动到0的位置
oDiv.onmouseenter = function (){
startMove(this, 0);
}
// 鼠标移出后,将div移动回-400位置隐藏
oDiv.onmouseleave = function (){
startMove(this, -400);
}
function startMove(dom, target){
clearInterval(timer);
var iSpeed = null;
timer = setInterval(function(){
iSpeed = (target - oDiv.offsetLeft) / 7;
iSpeed = iSpeed > 0 ? Math.ceil(iSpeed) : Math.floor(iSpeed);
if(oDiv.offsetLeft == target) {
clearInterval(timer);
}else{
oDiv.style.left = oDiv.offsetLeft + iSpeed + 'px';
}
}, 30);
}
</script>
多物体运动
<style>
div {
width: 100px;
height: 100px;
background: red;
opacity: 1; /* 不透明度 */
margin-bottom: 100px;
}
</style>
<div></div>
<div></div>
<div></div>
<script>
var timer = null;
var oDivArray = document.getElementsByTagName('div');
for (var i = 0; i < oDivArray.length; i++) {
oDivArray[i].onmouseenter = function () {
startMove(this, 400);
}
oDivArray[i].onmouseleave = function () {
startMove(this, 100);
}
}
function getStyle(dom, attr){
if(window.getComputedStyle){
return window.getComputedStyle(dom, null)[attr];
}else{
return dom.currentStyle[attr];
}
}
// 所有元素都缓冲直线运动
function startMove (dom, target) {
// 只清理当前dom的定时器,为每次传入的dom都分配一个定时器,可避免定时器被覆盖
// 多物体运动时应注意定时器覆盖问题,为每个运动物体分别分配定时器,启用和清理时避免冲突
clearInterval(dom.timer);
var iSpeed = null, // 速度
iCur = null; // 元素宽度
dom.timer = setInterval(function () {
// 获取元素宽度,返回值为100px,使用parseInt将其转化为整数100
iCur = parseInt( getStyle(dom, 'width') );
iSpeed = (target - iCur ) / 7;
iSpeed = iSpeed > 0 ? Math.ceil(iSpeed) : Math.floor(iSpeed);
if (iCur == target) {
clearInterval(dom.timer);
}else{
dom.style.width = iCur + iSpeed + 'px';
}
}, 30);
}
// 改进,元素可分别独自运动,缓冲向右运动、向下运动、透明度变化等
function startMove (dom, attr, target) {
clearInterval(dom.timer);
var iSpeed = null,
iCur = null;
dom.timer = setInterval(function () {
// 判断要更改的属性是否是透明度
if (attr == 'opcity') {
// 由于透明度的取值特殊,所以需要扩大100倍,计算后,再缩小100倍
iCur = parseFloat( getStyle(dom, attr) ) * 100;
}else {
iCur = parseInt( getStyle(dom, attr) );
}
iSpeed = (target - iCur) / 7;
iSpeed = iSpeed > 0 ? Math.ceil(iSpeed) : Math.floor(iSpeed);
if (iCur == target) {
clearInterval(dom.timer);
}
// 若更改的是透明度,缩小100倍
if (attr == 'opacity') {
dom.style.opacity = ( iCur + iSpeed ) / 100;
}else {
// 更改元素位置
dom.style[attr] = iCur + iSpeed + 'px';
}
}, 30);
}
</script>
多物体多值运动封装版
<style>
div {
position: absolute;
left: 0px;
width: 100px;
height: 100px;
background: red;
opacity: 1;
}
#topDiv {
top: 200px;
}
#bottomDiv {
top: 400px;
}
</style>
<div id='topDiv'></div>
<div id='bottomDiv'></div>
<script>
// 更改元素的多个值
// width:100→400,height:100→400,left:0→200,top:200→300,opacity:1→0.5
var oTopDiv = document.getElemensById('topDiv');
var oBottomDiv = document.getElementsById('bottomDiv');
oTopDiv.onclick = function () {
startMove(this, {width: 400, height: 400, left: 200, top: 300, opacity: 50}, function () {
startMove(oBottomDiv, {width: 400, height: 400, left: 200, top: 300, opacity: 50}, function () {
alert('over');
})
})
}
// 获取元素某一样式
function getStyle (dom, attr) {
if (window.getComputedStyle) {
return window.getComputedStyle(dom, null)[attr];
}else {
return dom.currentStyle[attr];
}
}
// 操作对象,目标属性数组,回调函数
function startMove (dom, attrObj, callback) {
clearInterval(dom.timer);
var iSpeed = null,
iCur = null;
dom.timer = setInterval(function () {
var bStop = ture;
for (var attr in attrObj) {
if (attr == 'opacity') {
iCur = parseFloat( getStyle(dom, attr) ) * 100;
}else {
iCur = parseInt( getStyle(dom, attr) );
}
iSpeed = (attrObj[attr] - iCur) / 7;
iSpeed = iSpeed > 0 ? Math.ceil(iSpeed) : Math.floor(iSpeed);
if (attr == 'opacity') {
dom.style.opacity = (iCur + iSpeed + 'px');
}
if(iCur != attrObj[attr]) {
bStop = false;
}
}
if (bStop) {
calerInterval(dom.timer);
// 逻辑与运算,判断callback为一个函数的时候,才执行callback
typeof callback == 'function' && callback();
}
})
}
</script>