Javascript 不会重新计算基于数组值的计算属性 问题空间
我正在渲染一些嵌套的余烬视图,以便创建拆分器窗格样式的UI。我想在第一次渲染视图时调整视图的大小,以便它们具有相同的宽度。我不希望我的子视图彼此对视,因此我使用Javascript 不会重新计算基于数组值的计算属性 问题空间,javascript,coffeescript,ember.js,Javascript,Coffeescript,Ember.js,我正在渲染一些嵌套的余烬视图,以便创建拆分器窗格样式的UI。我想在第一次渲染视图时调整视图的大小,以便它们具有相同的宽度。我不希望我的子视图彼此对视,因此我使用Ember.ContainerView的子类来保存我的内容和可拖动的拆分器句柄 我不能在容器视图上使用Ember.View#didinserelement,因为我需要等待子视图完全呈现 我的(尝试的)解决方案 我正在使用此答案中提供的代码:。这将向所有Ember.View实例添加属性isRendered,该属性在模板通过重新打开Ember
Ember.ContainerView
的子类来保存我的内容和可拖动的拆分器句柄
我不能在容器视图上使用Ember.View#didinserelement
,因为我需要等待子视图完全呈现
我的(尝试的)解决方案
我正在使用此答案中提供的代码:。这将向所有Ember.View
实例添加属性isRendered
,该属性在模板通过重新打开Ember触发didInsertElement
时自动设置。视图:
Ember.View.reopen
didInsertElement: ->
res = @_super();
@_setIsRendered();
res
_setIsRendered: ->
if (!! @$())
@set('isRendered', true)
else
Ember.run.next this, ->
@_setIsRendered()
我尝试重新打开Ember.ContainerView
以向所有容器视图添加childViewsRendered
属性,但Ember反对,并对childViews中只有一项的容器视图抛出了一些非常奇怪的IndexOutOfBounds错误
我最终将我的收藏代码放在以下mixin中:
App.ChildrenRendered = Ember.Mixin.create
childViewsRendered: (->
res = @get('childViews').everyProperty('isRendered')
console.log('childViewsRendered', res, this)
# Pointer to this most offensive object for debugging
window.wtf = this
res
).property('childViews.@each.isRendered')
_runChildViewsDidRender: (->
if @get('childViewsRendered')
console.log('trying to invoke childViewsDidRender')
Ember.tryInvoke(this, 'childViewsDidRender')
).observes('childViewsRendered')
然后我有一节课是这样的:
App.SplitterView = Ember.ContainerView.extend App.ChildrenRendered,
# ...(some properties)...
init: ->
child_views = @get('childViews')
child_views.pushObjects([App.WindowView.create(), App.WindowView.create()])
工作原理:
在任何视图渲染之前计算一次,因此变为App.SplitterView#childViewsRendered
false
- 视图由Ember处理(插入和渲染),并设置其自己的
属性fine and dandyisRendered
- 稍后运行
返回window.wtf.get('childview')。everyProperty('isRendered')
true
- 计算属性
不再更新自身childViewsRendered
数组元素成员上的虚拟值的计算属性似乎也不起作用childView
- 如果没有jsFiddle,我只能看你说的话和你提供的代码片段,但似乎你所要做的就是确保容器的所有子视图都在DOM中,然后再执行操作,是吗
如果是这样的话。。。当视图添加到
childview
时,您知道,它们会自动呈现并插入到DOM中。这一切都发生在同一个运行循环中。因此,要将某些函数的执行延迟到所有子函数都是“inDOM”,只需观察childview.@each
并使用Ember.run.next
将执行延迟到下一个RunLoop即可。这里有一个例子
App.SomeContainerView = Em.ContainerView.extend
init: ->
@_super() # run default init
# add 2 of our 4 views
@get('childViews').pushObjects [@aView.create(), @bView.create()]
# a non-cached (volatile) computed property to check if children are inDOM
# just used for demo purposes
childrenAreInDom: (->
@get('childViews').every (v) ->
v.state is "inDOM"
).property().volatile()
# our observer
observeChildren: (->
# if the container isn't inDOM yet the afterRender function we add below
# will handle it, if views are added/removed after that then we handle it here
return unless @state is "inDOM"
# output to console if every childview are inDOM
console.log "observeChildren", @get('childrenAreInDom')
# the above will always be false since we're still in the same RunLoop
# next RunLoop our function will run
Ember.run.next @, 'doWhatever'
).observes('childViews.@each') # observe changes in the childViews array
afterRender: ->
console.log "afterRender", @get('childrenAreInDom')
Ember.run.next @, 'doWhatever'
# the function we want to run eventually after children are inDOM
doWhatever: ->
console.log "doWhatever"
# print out childrenAreInDom one more time.. it will be true
console.log "childrenAreInDom:", @get('childrenAreInDom')
# some views to insert
aView: Em.View.extend
template: Em.Handlebars.compile("A")
bView: Em.View.extend
template: Em.Handlebars.compile("B")
cView: Em.View.extend
template: Em.Handlebars.compile("C")
dView: Em.View.extend
template: Em.Handlebars.compile("D")
如果模板中有{{view App.SomeContainerView}},在控制台中您会看到:
afterRender false
doWhatever
childrenAreInDom true
如果在容器已经在DOM中之后,通过pushObjects以编程方式添加cView和dView,您将看到
observeChildren false
doWhatever
childrenAreInDom true
即使这不完全是你想要的,希望它能帮助你达到你需要的地方,而不需要那些混搭的废话:D