在Ember.js中退出路由时如何*不*破坏视图
关于新的Ember.js路由系统(如上所述),如果我理解正确,当您退出路由时,视图将被破坏 是否有任何方法可以在退出路由时绕过视图的破坏,从而在用户重新进入路由时保留视图的状态在Ember.js中退出路由时如何*不*破坏视图,ember.js,ember-old-router,Ember.js,Ember Old Router,关于新的Ember.js路由系统(如上所述),如果我理解正确,当您退出路由时,视图将被破坏 是否有任何方法可以在退出路由时绕过视图的破坏,从而在用户重新进入路由时保留视图的状态 更新:看起来,除非在新管线中替换插座视图,否则视图不会被破坏。例如,如果您在某个{{outlet master}}中使用ViewA进入stateA,并且在{{outlet master}中使用ViewB进入stateB,则ViewB将替换ViewA。解决此问题的一种方法是在需要保留视图时定义多个出口,例如,{{outl
更新:看起来,除非在新管线中替换插座视图,否则视图不会被破坏。例如,如果您在某个{{outlet master}}中使用ViewA进入stateA,并且在{{outlet master}中使用ViewB进入stateB,则ViewB将替换ViewA。解决此问题的一种方法是在需要保留视图时定义多个出口,例如,{{outlet master1}}、{{outlet master2}}、 一个很好的特性是能够将一组视图传递给插座。还可以选择在退出路线时视图是被破坏还是被隐藏 这样,当用户重新输入视图时,视图的状态将被保留 路线 相反,我会将该信息存储在控制器(或状态管理器)中,以便在重新输入路由时,使用旧状态初始化新视图。这有意义吗?因此,例如,如果它是一个帖子列表,并且选择了一个帖子,那么您将在控制器(或状态管理器)中存储关于选择哪个帖子的数据。在访问了一个特定的帖子,然后返回到列表后,会选择相同的帖子
我可以想象这样一个用例,它不会很有用(例如,滚动到一个长列表中的特定位置),因此可能无法回答您的问题。我已经找到了如何修改布线系统的方法,以便插入插座的视图不会被破坏。首先,我覆盖把手
outlet
helper,以便它将Ember.OutletView
加载到{{outlet}
:
Ember.Handlebars.registerHelper('outlet', function(property, options) {
if (property && property.data && property.data.isRenderData) {
options = property;
property = 'view';
}
options.hash.currentViewBinding = "controller." + property;
return Ember.Handlebars.helpers.view.call(this, Ember.OutletView, options);
});
其中Ember.OutletView
扩展Ember.ContainerView
,如下所示:
Ember.OutletView = Ember.ContainerView.extend({
childViews: [],
_currentViewWillChange: Ember.beforeObserver( function() {
var childViews = this.get('childViews');
// Instead of removing currentView, just hide all childViews
childViews.setEach('isVisible', false);
}, 'currentView'),
_currentViewDidChange: Ember.observer( function() {
var childViews = this.get('childViews'),
currentView = this.get('currentView');
if (currentView) {
// Check if currentView is already within childViews array
// TODO: test
var alreadyPresent = childViews.find( function(child) {
if (Ember.View.isEqual(currentView, child, [])) {
return true;
}
});
if (!!alreadyPresent) {
alreadyPresent.set('isVisible', true);
} else {
childViews.pushObject(currentView);
}
}
}, 'currentView')
});
基本上,我们覆盖了\u currentViewWillChange()
,只隐藏所有子视图,而不是删除当前视图。然后在\u currentViewDidChange()
中,我们检查currentView
是否已经在childview
中,并相应地采取行动。Ember.View.isEqual是以下内容的修改版本:
是的,我不是说一个简单的选择,而是在一些情况下,你可能有一个用户已经部分完成的长表单,滚动一个长列表(正如你所说的)。。。因此,将所有这些信息存储到控制器中并在重新输入时更新视图是没有意义的。另一种方法是将视图实例存储在控制器中,并在每次进入路由时使用该实例。但我希望有更好的方法。也许还有更好的方法:比我更了解余烬的人(有很多)可能会回答扎克,我认为如果你把顶级插座变成一个ContainerView
,你就可以完成这些额外的功能。然后,您可以通过childViews
属性直接操作它的子视图,并控制子视图是被删除还是只是隐藏。containerView比将所有这些自定义逻辑放入(某种程度上是containerView的粗略复制)更合适。这不应该是可接受的解决方案。这是一个容器视图,不幸的是(仍然)需要此逻辑来防止视图拆分。
Ember.View.reopenClass({
isEqual: function(a, b, stack) {
// Identical objects are equal. `0 === -0`, but they aren't identical.
// See the Harmony `egal` proposal: http://wiki.ecmascript.org/doku.php?id=harmony:egal.
if (a === b) return a !== 0 || 1 / a == 1 / b;
// A strict comparison is necessary because `null == undefined`.
if (a == null || b == null) return a === b;
// Unwrap any wrapped objects.
if (a._chain) a = a._wrapped;
if (b._chain) b = b._wrapped;
// Compare `[[Class]]` names.
var className = toString.call(a);
if (className != toString.call(b)) return false;
if (typeof a != 'object' || typeof b != 'object') return false;
// Assume equality for cyclic structures. The algorithm for detecting cyclic
// structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
var length = stack.length;
while (length--) {
// Linear search. Performance is inversely proportional to the number of
// unique nested structures.
if (stack[length] == a) return true;
}
// Add the first object to the stack of traversed objects.
stack.push(a);
var size = 0, result = true;
// Recursively compare objects and arrays.
if (className == '[object Array]') {
// Compare array lengths to determine if a deep comparison is necessary.
size = a.length;
result = size == b.length;
if (result) {
// Deep compare the contents, ignoring non-numeric properties.
while (size--) {
// Ensure commutative equality for sparse arrays.
if (!(result = size in a == size in b && this.isEqual(a[size], b[size], stack))) break;
}
}
} else {
// Objects with different constructors are not equivalent.
if (a.get('constructor').toString() != b.get('constructor').toString()) {
return false;
}
// Deep compare objects.
for (var key in a) {
if (a.hasOwnProperty(key)) {
// Count the expected number of properties.
size++;
// Deep compare each member.
if ( !(result = b.hasOwnProperty(key) )) break;
}
}
}
// Remove the first object from the stack of traversed objects.
stack.pop();
return result;
}
});