【问题标题】:The code is not synchronized when manipulating the DOM with jQuery?用 jQuery 操作 DOM 时代码不同步?
【发布时间】:2012-05-09 01:32:58
【问题描述】:

我有这个功能:

var decreaseBar = function (barElement) {
   insertCSSTransitions(barElement);
   $(barElement).find('.bar').width(0);
}

insertCSSTransitions(barElement) 函数,这样做:

var insertCSSTransitions = function (barElement) {
      var timeBar = settings.timeBar;
      $(barElement).find('.bar').attr('style', 'transition:width ' + timeBar + 's; -moz-transition:width ' + timeBar + 's; -webkit-transition:width ' + timeBar + 's; -o-transition:width ' + timeBar + 's');
}

发生的情况是:$(barElement).find('.bar').width(0); 行将 width 设置为 0,然后 cssTransitions 的样式起作用。

因为,如果我将 decreaseBar 函数修改为此,它可以工作:

var decreaseBar = function (barElement) {
   insertCSSTransitions(barElement);

   // set a delay of 1 second before set to 0
   setTimeout(function() {
      $(barElement).find('.bar').width(0);
   }, 1000)
}

用jQuery操作DOM时代码不同步?

【问题讨论】:

  • 不,不是。浏览器环境是异步的。

标签: javascript jquery dom css-transitions


【解决方案1】:

这里可能发生的情况是,insertCSSTransitions() 所做的样式更改在您释放浏览器的控制权(重新绘制时)才会生效。

您真的只需要使用setTimeout(..., 1) 来确保在浏览器处理完transition 样式后完成对元素宽度的更改。

【讨论】:

  • setTimeout() 有时有效,有时无效。但是如果将元素的宽度设置为相同的宽度,它会起作用: $bar.width($bar.width());
【解决方案2】:

人们谈论异步行为就像它是圣杯一样,但是让 JS 在你想要的时候同步通常是更困难的任务。 Frame.js(与其他流控制库如 asnyc 和 flow.js 一样)旨在解决这个问题。在 Frame 中你会这样做:

var decreaseBar = function (barElement) {
    Frame(function(next)){
        insertCSSTransitions(barElement);
        next();
    });
    Frame(function(next)){
        $(barElement).find('.bar').width(0);
        next();
    });
    Frame.init();
}

【讨论】:

    【解决方案3】:

    使用回调?

    var decreaseBar = function (barElement) {
       insertCSSTransitions(barElement, function() {
           $(barElement).find('.bar').width(0);
       });
    }
    
    var insertCSSTransitions = function (barElement, callback) {
        var timeBar = settings.timeBar;
        $(barElement).find('.bar').attr('style', 'transition:width ' + timeBar + 's; -moz-transition:width ' + timeBar + 's; -webkit-transition:width ' + timeBar + 's; -o-transition:width ' + timeBar + 's');
    
        setTimeout(function() {callback.call();}, timebar*1000);
    }
    

    这只是一个简单的回调示例,它不会等待 CSS 转换发生,并且应该有一个简单的 typeof 检查来查看回调是否是一个函数,如果它也用于其他用途。

    编辑:

    正如 Pointy 指出的那样,回调并没有做太多事情,除了显示它是如何完成的等等。 将回调绑定到转换结束可能是要走的路,但是该属性有一堆前缀,在这里通过一些简单的浏览器检测解决了,但是那里有库用于检查浏览器中的实际支持。

    var insertCSSTransitions = function (barElement, callback) {
        var timeBar = settings.timeBar,
            transitionEnd = "TransitionEnd";
        if ($.browser.webkit) {transitionEnd = "webkitTransitionEnd";}
        else if ($.browser.mozilla) {transitionEnd = "transitionend";}
        else if ($.browser.opera) {transitionEnd = "oTransitionEnd"; }
    
        $(barElement).find('.bar')
                     .attr('style', 'transition:width ' + timeBar + 's; -moz-transition:width ' + timeBar + 's; -webkit-transition:width ' + timeBar + 's; -o-transition:width ' + timeBar + 's');
                     .on(transitionEnd, function() {
                         callback.call();
        });
    }
    

    【讨论】:

    • 我不明白你回调的目的,你回调的代码和我没有回调的代码一样,会一个接一个。你能再解释一下吗?
    • 是的,它和你的代码一模一样,加了回调? css 过渡有什么作用,它们需要多长时间,它们在 CSS 中是否设置为一秒? JS中没有“等待css转换”功能,因此与转换同时超时可能是要走的路,但回调将确保仅在插入函数完成后执行width(0),即就是,JS部分完成,CSS中设置的定时器没有JS回调。
    • 当callback.call();运行,页面中的dom不会添加'style'属性,因为浏览器没有重绘。
    • style 属性几乎是立即添加的,但是要更改样式,您应该考虑使用 css() 方法。同样,您的过渡是否在 CSS 中设置了计时器。
    • 这里的回调几乎没有用,除非它被设置为“transitionend”事件的事件处理程序(或相应的浏览器特定风格)。当转换完成时,它会在元素上触发,这就是问题的真正要求。
    【解决方案4】:

    除非进行 AJAX 调用,否则 JavaScript 始终是同步的:When is JavaScript synchronous?

    您的代码无法正常工作,因为您使用的 CSS 过渡与 JavaScript 不同步。 JavaScript 正在将样式转换“添加”到 DOM 中,一旦完成,继续前进。

    我不太确定您的功能的用途,因此很难提出更好的解决方案。总而言之,像你这样让 JavaScript 添加硬编码样式通常是不好的做法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-10-07
      • 2012-03-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-19
      相关资源
      最近更新 更多