我使用这个 jquery 通过每次点击来移动一个 div。
$(document).ready(function(){
$('#hero').click(function(){
$(this).animate({
left: '+=50px'
},300);
})
})
只要有可能更深入地了解纯 JS,我就想避免使用 jquery。
无论如何不使用jquery也能达到同样的效果吗?
我知道这会更复杂,但只是尝试学习。
我使用这个 jquery 通过每次点击来移动一个 div。
$(document).ready(function(){
$('#hero').click(function(){
$(this).animate({
left: '+=50px'
},300);
})
})
只要有可能更深入地了解纯 JS,我就想避免使用 jquery。
无论如何不使用jquery也能达到同样的效果吗?
我知道这会更复杂,但只是尝试学习。
您可以在 javascript 中使用相同的技术:
// get the object refrence
var hero_obj = document.getElementById('hero');
// attach the onclick event
hero_obj.onclick = function(){
this.style.left = ( parseInt(this.style.left, 10) + 50 ) + 'px'
};
但是效果不会像jquery那么流畅
这是带有动画的代码。此代码段仅适用于现代浏览器,但也很容易修改以与旧浏览器 (IE) 一起使用。(实际上只需要修复事件的附件。)
window.onload = function () {
var timer, k, intervals, kX, kY,
counter = 0,
hero = document.getElementById('hero'),
posX = hero.offsetLeft,
posY = hero.offsetTop,
anim = function (elem, params) {
posX += kX;
posY += kY;
elem.style.left = posX + 'px';
elem.style.top = posY + 'px';
if (counter > intervals) {
clearInterval(timer);
counter = 0;
} else {
counter++;
}
return;
},
move = function (elem, params) {
if (timer) {
clearInterval(timer);
counter = 0;
}
k = Math.atan2(params.left, params.top);
kX = Math.sin(k);
kY = Math.cos(k);
intervals = Math.floor(Math.sqrt(Math.pow(params.left, 2) + Math.pow(params.top, 2)));
timer = setInterval(function () {
anim(elem, params);
return;
}, params.speed);
return;
};
document.getElementById('hero').addEventListener('click', function (e) {
move(e.currentTarget, {left: 50, top: 0, speed: 0});
return;
}, false);
return;
}
如您所见,使用此代码,您还可以垂直移动元素并调整速度。要切换方向,只需添加-
到相应的属性。该代码仅使用像素作为单位,但如果需要,很容易修改。
将此功能代码转换为对象也很容易。也可以通过传递属性params.duration
而不是使用params.speed
and 进行一些高级计算kX
来添加类似 jQuery 的持续时间kY
。
在jsFiddle工作演示
几周前,我在vanilla-js.com上偶然发现了这个宝石:
var s = document.getElementById('thing').style;
s.opacity = 1;
(function(){(s.opacity-=.1)<0?s.display="none":setTimeout(arguments.callee,40)})();
我真的很喜欢代码的简单性和大小。优雅高效!
我left
根据上面的代码创建了一个影响您选择的元素属性的函数:
/* element: DOM element such as document.getElementById('hero')
distance: distance in pixels to move to the left such as 50 or 100 */
function moveBy(element, distance){
var target = isNaN(parseInt(s.left)) ? distance : parseInt(s.left) + distance;
(function(){
s.left = isNaN(parseInt(s.left)) ? '1px' : (parseInt(s.left) + 1).toString() + 'px';
if(parseInt(s.left) <= distance) setTimeout(arguments.callee, 40);
})();
}
您可以四处玩耍,看看在速度和平滑度方面符合您的喜好。在 jsfiddle 上尝试一下。
/* So you go: */
moveBy(document.getElementById('hero'), 50);
/* Or you can bind it to an event */
document.getElementById('hero').addEventListener('click', function(event){
moveBy(this, 50);
});
如果您愿意将其变得更好,那么需要什么样的解决方案才能将left
属性替换为translate
. 正如Paul Irish 在他的博客中所说,提供比使用(top-left-bottom-right)translate
移动元素更好的性能。TRBL
也可以添加某种缓动功能以使事情变得顺畅。
我需要在不使用框架的情况下创建一个动画解决方案。
对我来说,棘手的部分是处理与用户交互相关的中断/重新启动动画。我发现如果你的动画双发,你很快就会遇到麻烦。
这是在 github 上:https ://github.com/robCrawford/js-anim
有一些支持功能,但这里是主要动画:
function animate(el, prop, to, pxPerSecond, easing, callback){
/**
* Animate style property
* i.e. animate(div1, "width", 1100, 1000, "out", function(){console.log('div1 anim end')});
*
* @param el DOM element
* @param prop Property to animate
* @param to Destination property value
* @param pxPerSecond Speed of animation in pixels per second
* @param easing (optional) Easing type: "in" or "out"
* @param callback (optional) Function to call when animation is complete
*/
var frameDur = 10,
initPropVal = parseInt(getCurrCss(el, prop)),
distance = Math.abs(to-initPropVal),
easeVal = (easing==="in")?1.5:(easing==="out")?0.5:1, // >1 ease-in, <1 ease-out
elAnimData = getData(el, 'animData');
//Quit if already at 'to' val (still fire callback)
if(initPropVal===to){
if(callback)callback.call();
return;
}
//Init animData for el if first anim
if(!elAnimData){
elAnimData = {};
setData(el, {'animData':elAnimData});
}
//Get data for prop being animated or create entry
var animDataOb = elAnimData[prop];
if(!animDataOb)animDataOb = elAnimData[prop] = {};
//Don't re-initialise an existing animation i.e. same prop/to
if(animDataOb.to === to)return;
animDataOb.to = to; //Store 'to' val
//Clear any exisiting interval
if(animDataOb.intId){
clearInterval(animDataOb.intId);
animDataOb.intId = null;
}
//Create new anim
animDataOb.intId = (function(animDataOb){
var totalSteps = Math.round((distance/pxPerSecond)/(frameDur*.001)),
thisStep = 0;
return setInterval(function(){
var newVal = easeInOut(initPropVal, to, totalSteps, thisStep++, easeVal);
if(!isNaN(newVal))el.style[prop] = newVal + "px"; //Allow 0
if(thisStep > totalSteps)endAnim(animDataOb, callback);
}, frameDur);
})(animDataOb);
}
function endAnim(animDataOb, callback){
//End anim
clearInterval(animDataOb.intId);
animDataOb.intId = animDataOb.to = null;
if(callback)callback.call();
}