最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Using addClass() and CSS transition on render function in Backbone app not working correctly - Stack Overflow

programmeradmin2浏览0评论

In my backbone.js application, I'm trying to fade in the view element after it's been appended. However it doesn't work.

Live example here:

    var itemRender = view.render().el;

    $('#items-list').append(itemRender);
    $(itemRender).addClass('show'); 

However if I add a small setTimeout function, it works.

    var itemRender = view.render().el;

    $('#items-list').append(itemRender);

    setTimeout(function(){
        $(itemRender).addClass('show'); 
    },10);

Using fadeIn() also works but I prefer to use straight CSS for the transition as it's more efficient, and prefer not to use any setTimeout "hacks" to force it to work. Is there a callback I can use for append? Or any suggestions? The full code is below:

itemRender: function (item) {
    var view = new app.ItemView({ model: item }),
        itemName = item.get('name'),
        itemRender = view.render().el;

    $('#items-list').append(itemRender);
    $(itemRender).addClass('show');

    app.itemExists(itemName);
}

CSS/LESS:

#items-list li {
    padding: 0 10px;
    margin: 0 10px 10px;
    border: 1px solid @black;
    .border-radius(10px);
    position: relative;
    .opacity(0);
    .transition(opacity)
}

#items-list li.show {.opacity(1)}

In my backbone.js application, I'm trying to fade in the view element after it's been appended. However it doesn't work.

Live example here: http://metropolis.pagodabox.

    var itemRender = view.render().el;

    $('#items-list').append(itemRender);
    $(itemRender).addClass('show'); 

However if I add a small setTimeout function, it works.

    var itemRender = view.render().el;

    $('#items-list').append(itemRender);

    setTimeout(function(){
        $(itemRender).addClass('show'); 
    },10);

Using fadeIn() also works but I prefer to use straight CSS for the transition as it's more efficient, and prefer not to use any setTimeout "hacks" to force it to work. Is there a callback I can use for append? Or any suggestions? The full code is below:

itemRender: function (item) {
    var view = new app.ItemView({ model: item }),
        itemName = item.get('name'),
        itemRender = view.render().el;

    $('#items-list').append(itemRender);
    $(itemRender).addClass('show');

    app.itemExists(itemName);
}

CSS/LESS:

#items-list li {
    padding: 0 10px;
    margin: 0 10px 10px;
    border: 1px solid @black;
    .border-radius(10px);
    position: relative;
    .opacity(0);
    .transition(opacity)
}

#items-list li.show {.opacity(1)}
Share Improve this question edited Apr 27, 2013 at 19:24 HandiworkNYC. asked Apr 27, 2013 at 19:03 HandiworkNYC.HandiworkNYC. 11.1k25 gold badges95 silver badges156 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 9

This "hack" you mention (or some variant of it) is occasionally necessary for web development, simply due to the nature of how browsers render pages.

(NOTE: This is all from memory, so while the overall idea is right please take any details with a small grain of salt.)

Let's say you do the following:

$('#someElement').css('backgroundColor', 'red');
$('#someElement').css('backgroundColor', 'blue');

You might expect to see the background color of #someElement flash red for a brief moment, then turn blue right? However, that won't happen, because browsers try to optimize rendering performance by only rendering the final state at the end of the JS execution. As a result, the red background will never even appear on the page; all you'll ever see is the blue.

Similarly here, the difference between:

  1. append
  2. set class

and:

  1. append
  2. wait 1ms for the JS execution to finish
  3. set class

Is that the latter allows the element to enter the page and AFTER the JS is executed have its style change, while the former just applies the style change before the element gets shown.

So while in general window.setTimeout should be avoided, when you need to deal with these ... plications of browser rendeering, it's really the only way to go. Personally I like using the Underscore library's defer function:

var itemRender = view.render().el;

$('#items-list').append(itemRender);

_(function(){
    $(itemRender).addClass('show'); 
}).defer();

It's the same darn thing, but because it's encapsulated in a library function it feels less dirty to me :-) (and if the "post-render" logic is more than a line or two I can factor it in to a Backbone View method and do _(this.postRender).defer() inside my render method).

You can use CSS animations

@keyframes show {
  0%   { opacity: 0; }
  100% { opacity: 1; }
}

#items-list li {
    padding: 0 10px;
    margin: 0 10px 10px;
    border: 1px solid @black;
    .border-radius(10px);
    position: relative;
}
#items-list li.show {
    animation: show 1s;
}

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论