我已经找出如何修改路由系统,以便不会销毁插入到outlets中的视图。首先我覆盖了Handlebars中的outlet
辅助器,使其加载一个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');
childViews.setEach('isVisible', false);
}, 'currentView'),
_currentViewDidChange: Ember.observer( function() {
var childViews = this.get('childViews'),
currentView = this.get('currentView');
if (currentView) {
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')
});
基本上我们重写了_currentViewWillChange()
,只需隐藏所有的childViews
而不是删除currentView
。 然后在_currentViewDidChange()
中,我们检查currentView
是否已经在childViews
中,并相应地进行操作。 Ember.View.isEqual
是UnderscoreisEqual
的修改版本:
Ember.View.reopenClass({
isEqual: function(a, b, stack) {
if (a === b) return a !== 0 || 1 / a == 1 / b;
if (a == null || b == null) return a === b;
if (a._chain) a = a._wrapped;
if (b._chain) b = b._wrapped;
var className = toString.call(a);
if (className != toString.call(b)) return false;
if (typeof a != 'object' || typeof b != 'object') return false;
var length = stack.length;
while (length--) {
if (stack[length] == a) return true;
}
stack.push(a);
var size = 0, result = true;
if (className == '[object Array]') {
size = a.length;
result = size == b.length;
if (result) {
while (size--) {
if (!(result = size in a == size in b && this.isEqual(a[size], b[size], stack))) break;
}
}
} else {
if (a.get('constructor').toString() != b.get('constructor').toString()) {
return false;
}
for (var key in a) {
if (a.hasOwnProperty(key)) {
size++;
if ( !(result = b.hasOwnProperty(key) )) break;
}
}
}
stack.pop();
return result;
}
});