Tôi đã tìm ra cách sửa đổi hệ thống định tuyến để các chế độ xem được chèn vào các cửa hàng không bị hủy. Trước tiên tôi ghi đè lên các helper tay lái outlet
, để nó tải một Ember.OutletView
vào {{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);
});
đâu Ember.OutletView
kéo dài Ember.ContainerView
như sau:
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')
});
Về cơ bản chúng tôi ghi đè _currentViewWillChange()
và chỉ ẩn tất cả childViews
thay vì loại bỏ số currentView
. Sau đó, trong _currentViewDidChange()
, chúng tôi kiểm tra xem currentView
có nằm trong số childViews
và hành động tương ứng hay không. Các Ember.View.isEqual
là một phiên bản sửa đổi của Underscore isEqual
:
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;
}
});
Zack, Tôi nghĩ rằng bạn có thể thực hiện những tính năng bổ sung nếu bạn thực hiện mức cửa hàng hàng đầu của bạn một 'ContainerView'. Sau đó, bạn có thể trực tiếp thao tác với trẻ em, thông qua thuộc tính 'childViews' và kiểm soát nếu chế độ xem con bị xóa hoặc chỉ bị ẩn. –