我想做的很简单:在当前路由中的所有视图完成渲染后,从 jQuery 和 jsPlumb 库中执行一些(实际上很多)视图层 Javascript 代码。在从这个解决方案中获得一些帮助并发现 ember-latest 刚刚更新为包含afterRender
hook 之后,我决定升级。我现在有了万能的afterRender
钩子。
我插入到 dom 中的所有视图都有一个block
与之关联的类。因此,我一直在测试以查看是否所有视图都在 dom 中的方式正在使用$('.block').size()
并查看它是否与预期的数字匹配。
但是,当我尝试在我的应用程序中使用这个钩子时,我遇到了一些问题。afterRender
在调用connectOutlets
. 当我打印出 dom 中的块数时,我总是只得到 1 个块,而应该有 10 个。
如果我将此代码放在didInsertElement
我的本地block
视图中:
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 个块,之后我得到了全部 10 个。我不知道为什么。但这里的主要问题是,如果我把钩子放在里面didInsertElement
,代码会根据数据执行任意数量的视图(在这个例子中是 10)。但是,我只想在所有视图完成渲染后运行一次此代码。
请注意,我正在使用的视图具有嵌套数据。我试图在 jsFiddle 上重现这一点,但我失败了,因为它似乎在小提琴上都能找到和花花公子。也许是因为我的观点很大而且很复杂,它会导致一些同步问题?无论如何,我认为我们可以使用小提琴作为讨论解决方案的一种方式,我可以在本地对其进行测试。
我试图解决这个问题的一个技巧是安排我的代码在 500 毫秒延迟后使用Ember.run.later
. 这确实解决了我本地机器上的问题。但是,使用计时器来做这件事是非常牛粪,并且不能可靠地工作,因为不同的浏览器或机器可能需要更长的时间来呈现视图。
这是一个可以重现的问题,我已经花了很多时间试图找到解决方案。我将不胜感激在此处重现问题或找到解决方案的任何帮助。
编辑(解决方法):感谢您帮助我解决此问题,并通过查看有关类似问题的这篇文章,我想出了以下临时解决方法,我将其放入路由器代码中:
# 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
正如卢克指出的那样,这里的问题是我的嵌套视图正在多个 RunLoop 上呈现。当我刷新浏览器时,我blockies number ...: 1
每次都会得到不同数量的输出,在我的测试期间任何地方都在 4 到 10 次之间。
在我看来,这不是一个很好的解决方案,但它似乎适用于我的用例。我觉得这里需要另一个钩子,当保证视图中的所有元素都可以通过 jQuery 选择器访问时,它允许访问 DOM,但也许我在这里遗漏了一些东西。