使用带有嵌套视图的 `afterRender` 钩子 [英] Using `afterRender` hook with nested views

查看:19
本文介绍了使用带有嵌套视图的 `afterRender` 钩子的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果你想先看代码,这里是jsFiddle

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

What I want to do is simple: execute some (actually a lot) of view layer Javascript code from jQuery and jsPlumb libraries after ALL the views in the current route have finished rendering. After getting some help from this solution and finding that ember-latest has just been updated to include afterRender hook, I decided to upgrade. I now have the almighty afterRender hook.

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

All the views I am inserting into the dom have a block class associated with them. So the way I have been testing to see if all the views are in the dom is using $('.block').size() and seeing if it matches expected number.

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

However I am facing some issues when I try to use this hook in my application. I first tried to call the afterRender in the router, after the calls to connectOutlets. I always get only 1 block when I print out the number of blocks in dom while there should be 10.

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

If I put this code in didInsertElement of my local block view:

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).但是,我只想在所有视图完成渲染后运行此代码一次.

For some reason the first iteration I only get 1 block in the dom and after that I get all 10. I am not sure why. But the main issue here is that if I put the hook inside didInsertElement, the code gets executed for an arbitrary number of views depending on data (in this example 10). However I only want to run this code once after all views have finished rendering.

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

Note that the view I am working with has nested data. I tried to reproduce this on jsFiddle, but I failed in the sense that it seems to work all find and dandy on the fiddle. Maybe because my views are big and complex it is causing some synchronization issues? In any event, I think we can use the fiddle as a way to discuss a solution and I can test it locally.

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

One hack I tried to do to get around the issue is to schedule my code to run after 500ms delay using Ember.run.later. That did solve the issue on my local machine. However, using a timer to do this is very sheep dung and does not work reliably since different browsers or machines may take longer to render the views.

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

This is a though one to reproduce and I have already spent much time trying to find a solution. I would appreciate any help in reproducing the problem here or finding a solution.

编辑(解决方法):感谢您帮助我解决此问题,并查看 this关于类似问题的帖子,我想出了以下临时解决方法,并将其放入路由器代码中:

Edit (workaround): Thanks to look for helping me troubleshoot this problem, and by looking at this post about a similar problem, I came up with the following temporary workaround, which I put inside the router code:

    # 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 次.

As Luke pointed out, the problem here is that my nested views are being rendered over several RunLoops. when I refresh the browser I get a different number of blockies number ...: 1 output everytime, anywhere between 4 and 10 times during my tests.

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

In my opinion this is not a very good solution, but it seems to work for my use case. I feel that there is a need here for another hook that allows one to access DOM when it is guaranteed all the elements from views are accessible through jQuery selectors, but perhaps I am missing something here.

推荐答案

我问过 Kris Selden 这个问题,他说afterRender 是在渲染队列为那个运行循环完全刷新之后;我猜这已经结束了不止一个循环"

I ran this question past Kris Selden, and he said "afterRender is after the render queue is totally flushed for that run loop; I'm guessing this is over more than one loop"

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

The most likely possibility is that you have a record array loading. Perhaps it starts with one item and then 9 more load in later. If you rule out data loading, perhaps you have an Ember.run.next or Ember.run.later somewhere in your code?

这篇关于使用带有嵌套视图的 `afterRender` 钩子的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆