为什么我不能在骨干视图中获得元素的高度?

时间:2014-10-24 23:07:48

标签: javascript jquery backbone.js

我试图在渲染后重新定位骨干视图中的元素,但无法获得高度。我已经开始使用setTimeout,但我仍然非常困惑和沮丧。为什么height()仅在主干渲染函数内返回null

我设法在jsfiddle中重现:http://jsfiddle.net/turpana/3nh9916a/2/

2 个答案:

答案 0 :(得分:1)

这是因为在调用view.$el之后将render插入到DOM中而不是之前。如果在实例化视图时指定el

var view = new View( { el : $('.bb-container') } ); 

然后this.$el中的render已经插入到DOM中,您的height()将正常工作updated jsfiddle

// in backbone view
var View = Backbone.View.extend({
    render: function () {
        this.$el.html('<p class="hello">hello</p>');
        var heightInline = $('.hello').height();
        setTimeout(function () {
            var heightInTimeout = $('.hello').height();
            $('.heights').append(
                '<p><strong>In backbone view:</strong></p>'
                + '<p>height inline: ' + heightInline + '</p>'
                + '<p>height after 1 ms: ' + heightInTimeout + '</p>'
             );

        }, 1);
        return this;
    }
});
var view = new View( { el : $('.bb-container') } ) 
view.render()
// just jquery
$('.jq-container').html('<p class="hello-again">hello again</p>');
var jqHeightInline = $('.hello-again').height();
$('.heights').append(
    '<p><strong>With just jQuery:</strong></p>'
    + '<p>height: ' + jqHeightInline + '</p>'
    );

答案 1 :(得分:1)

尝试使用这样的render,您应该更好地了解正在发生的事情:

render: function () {
    this.$el.html('<p class="hello">hello</p>');
    console.log('In render:');
    console.log('There is a .hello:', $('.hello').length !== 0);
    console.log('And it has height:', $('.hello').height());
    console.log('There is a .hello in this.el:', this.$('.hello').length !== 0);
    console.log('And it has height:', this.$('.hello').height());
    setTimeout(function () {
        console.log('After timeout:');
        console.log('There is a .hello:', $('.hello').length !== 0);
        console.log('And it has height:', $('.hello').height());
        console.log('There is a .hello in this.el:', this.$('.hello').length !== 0);
        console.log('And it has height:', this.$('.hello').height());
    }, 1);
    return this;
}

演示:http://jsfiddle.net/ambiguous/7c04rma4/

您将在控制台中获得如下输出:

In render:
There is a .hello: false
And it has height: null
There is a .hello in this.el: true
And it has height: 0

After timeout:
There is a .hello: true
And it has height: 18
There is a .hello in this.el: true
And it has height: 18

您的null高度为$('.hello'),因为.hello为空。在之后 之后, el已经添加到DOM中并且之后发生 1}}返回。

如果您切换到render,您会找到该元素(因为它位于this.$('.hello')内,this.el内搜索this.$。当然,你的高度为零,所以这也不是非常有用。为什么高度为零?高度为零,因为浏览器在呈现之前不知道this.el有多大。同样,在 <p>返回后发生了这种情况。

您在render回调中获得了有用的结果,因为只有在setTimeout返回之后以及所有内容都添加到DOM之后才会触发。 JavaScript是单线程的,因此在浏览器再次获得控制权并且浏览器已清除其工作队列(包括DOM更新和呈现)之前,不会触发render回调。您有时会看到_.defersetTimeout来电,以便利用此功能。

有两种常见的方法摆脱这种困境:

  1. 使用setTimeout(..., 0)setTimeout技巧以正确的顺序发生事情。这假设调用者将立即将内容放入DOM中。
  2. 添加一个明确的“您已经呈现并添加到页面中”回调您的视图,并确保您的视图使用的任何内容都会在适当的时候调用回调。