我有一段代码应该移动this图片(id =' background'),我已在本地下载,并且非常大。当我将鼠标悬停在某个div的顶部时,它应该移动。然后,这会更改不透明度CSS值,而后者又由js检测到,然后使图像移动。 js代码如下所示:
setInterval(function(){
var element = document.getElementById('background'),
style = window.getComputedStyle(element),
left = style.getPropertyValue('left');
left = left.replace(/px/g, "")
left = parseInt(left,10)
if(getOpacity('rightbar') == .5){
document.getElementById('background').style.left = left - 8 + 'px'
}
if(getOpacity('leftbar') == .5){
document.getElementById('background').style.left = left + 8 + 'px'
}
},10)
getOpacity(idName)
函数如下所示:
function getOpacity(param){
var element = document.getElementById(param),
style = window.getComputedStyle(element),
opacity = style.getPropertyValue('opacity');
return opacity
}
所以问题在于,无论我使用什么移动值或setInteveral
时间,动画总是会变得迟钝。是否有办法使用vanilla js来平滑,或者更好的是,废弃不透明度检测并使用CSS完成所有操作?
当我将上述代码放在fiddle中时,它工作正常,但当它实际运行完整浏览器时(在我个人的Chrome窗口中),它看起来像this。
注意:我在4k显示器上运行这个完整的浏览器窗口,这对于处理chrome来说太多了吗?
答案 0 :(得分:1)
requestAnimationFrame
代替setInterval
这表示您希望在下次重绘之前执行某些操作。您提供的回调每帧执行一次。
(如果这很重要:requestAnimationFrame
在IE9及以下版本中不起作用。)
使用requestAnimationFrame
和使用setInterval
时,帧之间的时差会有所不同。
您可以在开发人员工具栏中使用以下内容验证自己:
var last = new Date();
function onFrame(){
var now = new Date();
console.log(new Date() - last);
last = now;
requestAnimationFrame(onFrame);
}
onFrame();
开发人员控制台将以ms为单位输出帧时间,如下所示:
16
17
17
15
19
...
如果您在平均间隔时增加固定金额的位置(例如不透明度不明显),则动画看起来会呈锯齿状。所以,不要做left = left + 8;
,而是根据当前时间计算动画中的哪个位置,如下所示:
var myElement = ...;
var initialOpacity = 1.0;
var targetOpacity = 0.5;
var duration = 2000;
var startTime = new Date();
function animation() {
var delta = Math.min(1, (new Date() - startTime) / duration);
// delta is now a number in the range [0 ... 1]
myElement.style.opacity = initialOpacity + delta * (targetOpacity - initialOpacity);
if (delta < 1) requestAnimationFrame(animation);
}
requestAnimationFrame(animation);
是的,这个例子补充了不透明度而不是位置,但是你得到了这个想法 - 你的老师不能要求你复制粘贴; - )
假设您的图像的初始位置与视口无关(例如,left: -10%
),则无需在每一帧上读取位置。
当您的JavaScript是唯一更改left
属性的内容时,为什么要从CSS中读取它?将其保存在变量中,并将其设置为JavaScript中的CSS。
var initialX = ComputeCssXPosition(myElement);
...
function animate() {
...
myElement.style.left = computedNewXPosition;
}
如果您想在用户悬停元素时更改帖子,请在JS中使用鼠标事件。
myElement.addEventListener('mouseover', function (ev) { ... });
myElement.addEventListener('mouseout', function (ev) { ... });
answer by Shomz已经涵盖。
答案 1 :(得分:0)
最好的方法是使用requestAnimationFrame
代替setInterval
而不是检查样式更改,但是使用鼠标悬停监听器(过多的通信:CSS-&gt; JS-&gt; CSS- &GT; JS ...)。见这里:https://jsfiddle.net/yqpun3eb/4/
但是,如果您仍想使用setInterval
,则只需将转换CSS规则放在background
元素上即可。例如:
#background {transition: left 0.2s linear}
这样可以消除所有的值变化,因为CSS的表现更好,所以即使在4K屏幕上也应该没问题。问题是您的更改可以跳过8个像素。
似乎在我的机器上以0.2秒工作:https://jsfiddle.net/yqpun3eb/3/
哦,顺便说一下。你想要良好的表现,但为什么要用这个来强奸系统:
function getOpacity(param){
var element = document.getElementById(param),
style = window.getComputedStyle(element),
opacity = style.getPropertyValue('opacity');
return opacity
}
这不会创建额外的变量(无论如何你都不需要):
function getOpacity(param){
return window.getComputedStyle(document.getElementById(param))
.getPropertyValue('opacity');
}
最后,这是使用requestAnimationFrame
稍微优化的版本(我将如何操作+使用听众而不是阅读样式值):https://jsfiddle.net/yqpun3eb/4/