【问题标题】:Using `afterRender` hook with nested views在嵌套视图中使用 `afterRender` 钩子
【发布时间】:2012-11-28 16:52:31
【问题描述】:

Here is the jsFiddle if you like to see code first

我想做的很简单:在当前路由中的所有视图完成渲染后,从 jQuery 和 jsPlumb 库中执行一些(实际上很多)视图层 Javascript 代码。在得到this solution 的帮助并发现 ember-latest 刚刚更新为包含afterRender 挂钩后,我决定升级。我现在拥有了全能的afterRender 钩子。

我插入到 dom 中的所有视图都有一个与之关联的 block 类。因此,我一直在测试查看是否所有视图都在 dom 中的方法是使用 $('.block').size() 并查看它是否与预期的数字匹配。

但是,当我尝试在我的应用程序中使用此挂钩时,我遇到了一些问题。在调用connectOutlets 之后,我首先尝试在路由器中调用afterRender。当我打印出 dom 中的块数时,我总是只得到 1 个块,而应该有 10 个。

如果我将此代码放在本地block 视图的didInsertElement 中:

didInsertElement: () ->
    knob = this.$("##{@get 'knobId'}")
    name = this.$(".name")
    main = this.$(".main") #block html content will be injected into main
    knob.hide()

    Ember.run.scheduleOnce('afterRender', this, ()->
      console.log ">> block count: ", $(".block").size()
    )
    ...

然后我得到以下输出:

>> block count: 1
>> block count: 10
>> block count: 10
>> block count: 10
>> block count: 10
>> block count: 10
>> block count: 10
>> block count: 10
>> block count: 10
>> block count: 10

由于某种原因,第一次迭代我在 dom 中只得到了 1 个 block,之后我得到了全部 10 个。我不知道为什么。但这里的主要问题是,如果我将钩子放在didInsertElement 中,代码将根据数据执行任意数量的视图(在本例中为 10)。但是,我只想在所有视图完成渲染后运行一次此代码。

请注意,我正在使用的视图具有嵌套数据。我试图reproduce this on jsFiddle, 但我失败了,因为它似乎在小提琴上找到了所有花花公子。也许是因为我的观点很大而且很复杂,它会导致一些同步问题?无论如何,我认为我们可以使用小提琴作为讨论解决方案的一种方式,我可以在本地对其进行测试。

我试图解决这个问题的一个技巧是使用Ember.run.later 安排我的代码在延迟 500 毫秒后运行。这确实解决了我本地机器上的问题。然而,使用计时器来做这件事是非常牛逼的,并且不能可靠地工作,因为不同的浏览器或机器可能需要更长的时间来呈现视图。

这是一个可以重现的问题,我已经花了很多时间试图找到解决方案。如果能在此处重现问题或找到解决方案,我将不胜感激。

编辑(解决方法):感谢您帮助我解决此问题,并通过查看this post about a similar problem,我想出了以下临时解决方法,我将其放入路由器代码中:

    # Keep trying until there are two or more blocks in DOM
    blocksLoaded = ->
      console.log "blocks number ...: ", $('.block').size()
      if $('.block').size() > 1
        console.log "Yay!...we have ", $('.block').size()
        startTraversingBlocks()
      else
        Ember.run.next(this, ()->
          blocksLoaded()
        )

    blocksLoaded()

这个输出:

blockies number ...: 0
blockies number ...: 1
blockies number ...: 1
blockies number ...: 1
...
blockies number ...: 1
blockies number ...: 10
Yay!...we have 10

正如 Luke 所指出的,这里的问题是我的嵌套视图是在多个 RunLoop 上呈现的。当我刷新浏览器时,我每次都会得到不同数量的blockies number ...: 1 输出,在我的测试过程中会出现 4 到 10 次。

在我看来,这不是一个很好的解决方案,但它似乎适用于我的用例。我觉得这里需要另一个钩子,当保证视图中的所有元素都可以通过 jQuery 选择器访问时,它允许访问 DOM,但也许我在这里遗漏了一些东西。

【问题讨论】:

    标签: ember.js


    【解决方案1】:

    我向 Kris Selden 提出了这个问题,他说“afterRender 是在该运行循环的渲染队列完全刷新之后;我猜这超过了一个循环”

    最有可能的是您加载了一个记录数组。也许它从一个项目开始,然后再加载 9 个。如果您排除数据加载,也许您的代码中有Ember.run.nextEmber.run.later

    【讨论】:

    • 我注释掉了 Ember.run 的所有其他用途,但我仍然只获得 1 次查看。这听起来更像你描述的第一个场景。正如我所提到的,我用于此视图的数据是嵌套的,并且其中有视图数组。我不认为我明确告诉 ember 单独渲染第一个视图。如果我们假设这是第一种情况,您能否再解释一下我可以做些什么来缓解这个问题?
    • 如果您知道您期望超过一个项目,您可以使用条件属性将视图包装在 {{#if ...}} 句柄帮助器中,当数量超过时计算为 true 1. 我们在我们的应用程序中遇到了类似的问题,因为 1 项被侧载,然后我们执行查询以加载其余项。
    • 好吧,这听起来很有希望,但我不确定我是否理解得很好。我会把这样的条件放在哪里?在视图类定义中?这是你可以在我提供的小提琴中给我看的东西吗?在我的车把中,我通过引用回 this 来嵌套视图,所以我不清楚如何实现你所说的。
    • 是的,我期待 2 个或更多项目(或视图)
    • 这里有一个更新,目的是显示#if 的去向。 jsfiddle.net/vPbM4/5
    猜你喜欢
    • 2013-09-04
    • 2014-05-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-10
    • 1970-01-01
    • 2020-09-10
    • 2021-11-09
    相关资源
    最近更新 更多