jQuery addClass 方法链接以执行 CSS 转换

jQuery addClass method chaining to perform CSS transitions

我想做什么(坏了):

<div></div>
<button>go</button>
$('button').click(function () {
    $('div').css({
        'transition': 'left 1000ms'
    }).addClass('left').addClass('left_more');
});

http://jsfiddle.net/0bm4wq7h/13/

仍然破产:

<div></div>
<button>go</button>
$('button').click(function () {
    $('div').css({
        'transition': 'left 1000ms'
    }).addClass('left');
    console.log('test');
    $('div').addClass('left_more');
});

http://jsfiddle.net/fwL3dwz2/3/

但这有效:

<div></div>
<button>go</button>
$('button').click(function () {
    $('div').css({
        'transition': 'left 1000ms'
    }).addClass('left');
    console.log($('div').css('left'));
    $('div').addClass('left_more');
});

http://jsfiddle.net/j8x0dzbz/5/

我知道我的 CSS 过渡需要一个起点。这就是为什么我添加了 left class.

为什么 jQuery 直到我的 #3 才进行转换?

更新:

所以我接受了 Stryner 的回答,因为它对我有用,现在我又遇到了同样的问题。上面的代码是 JavaScript:

的简化版本
$('#screen_wrapper img:eq(0)').removeClass().addClass('prep'); //starting point
window.getComputedStyle(document.getElementById('photo'+0)).left; //force the the styling to get recomputated using raw JavaScript 
$('#screen_wrapper img:eq(0)').css('left');//force the the styling to get recomputated using jQuery
$('#screen_wrapper img:eq(0)').addClass('animate_in');//animate to the "animate_in" class coordinates from the "prep" class coordinates

发生的事情是我从 prep class.

之前的坐标开始获取动画

这是 prep class:

#screen_wrapper img.prep {
    top: 0px;
    left: 506px;
}

但图像实际上是从这个 class 开始的,它是使用 removeClass() jQuery 方法删除的:

.animate_out {
    visibility: visible;
    top: 0px;
    left: -506px;
}

transition 属性 工作正常:

$('#screen_wrapper img').css('transition','left 1000ms');

我怀疑这些 force 重新计算样式:

window.getComputedStyle(document.getElementById('photo'+0)).left;
$('#screen_wrapper img:eq(0)').css('left');

我正在使用 Chromium:

Version 45.0.2454.101 Ubuntu 14.04 (64-bit)

更新

它不起作用的例子: http://jsfiddle.net/me8ukkLe/12/

"CSS3 transitions allows you to change property values smoothly (from one value to another), over a given duration."

第一个场景发布:

为了使 css 过渡正常工作,您需要将 css 属性 指定给要进行过渡的元素。在您的示例中,您正在 left 属性 上进行转换,但它的初始值未在 div css.

中定义

为了修复它,只需添加 left 属性.

div {
    position: absolute;
    width: 10px;
    height: 10px;
    background-color: red;
    left: 0px;
}

工作示例:http://jsfiddle.net/0bm4wq7h/14/

发布的第二个场景与发布的第三个场景:

尽管两个示例都没有为 div 定义 left 属性,但与第二个场景相比,第三个场景的工作原理是因为延迟由 console.log 引起。

在第一个语句中,

$('div').css({
        'transition': 'left 1000ms'
    }).addClass('left');

class left 添加到 div 元素,后者在内部添加 left 属性。但是添加 console.log($('div').css('left') 会调用 window.getComputedStyle (如 Stryner 所述),它会注册计算值并添加 $('div').addClass('left_more'); 基本上让它有机会执行从 left : 100pxleft : 600px 的转换。

好问题!这种行为一开始肯定看起来很奇怪。解释清楚这一点也有点棘手,但首先,请了解以下内容:

1) Javascript 函数自动执行

在 JS 中,函数总是从头到尾 运行,中间没有任何其他操作发生的可能性。这就等于说JS是单线程语言.

2) 浏览器也无法中断javascript

不仅JS代码不会运行ning在一个函数中途被阻止,代码是运行ning的浏览器选项卡也不会插话!这意味着当 JS 函数 运行ning 时,网页上的(几乎)所有内容(重绘、动画、样式表应用程序等)都会停止。如果你想测试这个,你可以在控制台中尝试运行ning while (true) { var i = 'yo'; }。 (警告:这会让你难过)

3) JS 函数内部的状态对浏览器是不可见的

因为浏览器不能在 JS 函数中间中断,这意味着浏览器永远无法知道在该函数中途发生的任何状态。浏览器只能根据函数完成后保持的状态进行操作。不清楚?举例说明:

var someGlobalValue = null;

function lol() {
    someGlobalValue = 'hi';
    someGlobalValue = 'hello';
    someGlobalValue = 'ok';
}

当函数 lol 为 运行 时,someGlobalValue 会采用多个值,但浏览器将 只会知道最后一个值 , 因为它必须在中途插话才能看到其他人(这是它做不到的!)

4) CSS JS 函数内部的状态同样对浏览器不可见

css州也是如此! (现在您可能会看到,实际上我正在开始回答您的问题)。

如果调用以下函数:

function lol() {
    $('.thing').css('left', '10px');
    $('.thing').css('left', '30px');
}

浏览器 永远不会 应用 left: 10px 值,因为它不会在函数中途执行任何操作!浏览器只能使用函数的结果,即完成的结果。

正在回答您的问题!!

fiddle 1

left_more class 紧跟在 left class 之后 - 浏览器永远不会看到 left class,并应用css 函数结束后的样式 - 应用 left_more class,但由于没有初始左值,因此没有动画。 (css 级联;虽然两个 class 都存在,但 left_more 完全覆盖 left

fiddle 2

同样的问题 - left class 在浏览器可以处理之前被覆盖

fiddle 3

这是有效的,因为该值是通过调用 css 设置的,然后不会被覆盖,因为 addClass 用于设置值应该动画到的位置。 console.log 无关紧要 - 重要的是 css 函数调用。一旦该函数完成,就会有两条信息,一条是 css 值,另一条是 class 值。这与另一个例子形成对比,在另一个例子中,函数 运行s 之后只剩下 一条 条信息:class 值。

如果您只想使用 classes,并且仍然要进行转换,则流程必须如下所示:

1) 添加 left class 2)退出函数,允许浏览器查看状态 3) 添加left_moreclass

对不起这篇文章哈哈。但我认为由于问题的微妙性,这需要很长的解释。

当它调用 $('div').css('left') 时,您的转换在案例三中有效,因为 jQuery 将调用 Tim Taubert(Mozilla 员工)的方法 window.getComputedStyle (or a very similar method depending on browser compatibility issues). In a blog post,技巧如下:

getComputedStyle() in combination with accessing a property value actually flushes all pending style changes and forces the layout engine to compute our <div>’s current state.

在不强制重新计算布局的情况下,重新计算会延迟到添加了 类(leftleft-more)之后,这将计算其在 400px 的位置.

Example Fiddle - 使用 getComputedStyle 并访问 .left

这里有几个问题。在给出的示例中,添加第一个 left class 时不会发生转换的原因是,为了让渲染引擎为 属性 设置动画,属性 需要已经有一个值。在这种情况下,left 没有值,因此不会发生转换。

链接时不起作用的原因是因为特异性。 jQuery 将添加两个 classes,并且当调用呈现页面时,由于它们共享的特殊性,将应用最后添加的 left 定义。

在单独的时间添加 class 而不是链式添加似乎起作用的原因是,当 console.log 访问 css 元素的值。 Stryner 在他的回答中指出了这一点: 。这是一个非常好的发现。

这是一个应用示例,因此无需猜测 left 的值。

发生的事情的实质是找到元素的偏移量以获得左侧的像素偏移量。然后将该值应用于左侧样式 属性。那时,当元素仍然没有改变位置时,渲染引擎被调用以更新左侧 属性。然后删除 属性 以确保特异性不会优先于 class 定义,然后应用 class 定义。这将有助于第一次相遇时的过渡。

jsFiddle Demo

$('button').click(function() {
    $('div').css({'transition':'left 1000ms'}).each(function(){ 
        $(this).css('left',$(this).offset().left); 
        window.getComputedStyle(this,null).getPropertyValue("left");
    }).css('left','').addClass('left');
});
button {
    margin-top: 30px;
}

div {
    position: absolute;
    width: 10px;
    height: 10px;
    background-color: red;
}

.left {
    left: 100px;
}

.left_more {
    left: 400px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div></div>
<button>go</button>