我正在使用JQuery mobile expandable list
和Knockout.js
组合的页面上工作。我已经编写了允许构建 ViewModel 树结构并将其绑定到可扩展列表的机制。由于某些树节点可能很大,我使用koncokout :if
了绑定,因此节点在扩展之前不会被渲染(在第一页加载时构建了完整模型,但只渲染了 20 条记录)。有一次,当子节点的子节点仍然打开并且模型不同步时,我遇到了父节点被关闭的问题(在重新打开父节点时,子节点的子节点将被隐藏,因为根据模型它们从未关闭过)。MutationObservable
因此,如果节点从DOM
树中“蒸发”到为该节点的所有子节点设置模型以关闭,我已经习惯于处理这些情况。
function ShowChildren(data, element) {
if (data.IsExpanded != undefined) {
data.IsExpanded(!data.IsExpanded());
if (data.IsExpanded()) {
var childContentElements = $(element).parent().find('.ui-collapsible-content');
childContentElements.attr('data-bind','visible : $parent.IsExpanded != undefined && $parent.IsExpanded()');
AttachVisibilityChangedEventHandler({ targets: childContentElements, eventHandler: VisibilityChangedEventHandler });
$.each(childContentElements, function (i, item) { item.addEventListener('DOMNodeRemovedFromDocument', TreeNodeClosedEventHandler); });
$("[data-role='none']").attr('data-role','collapsible');
$("[data-role='collapsible-set'][data-onthemovedatasourceid='bcAccount']").trigger('create');
OnCollapsibleSetCreateJQueryMobileUI(element);
$.each($.grep($(element).parent().parent().find(">[data-role='collapsible']").find(">.ui-collapsible-content:not(.ui-collapsible-content-collapsed)").siblings(), function (item) { return element != item; }), function (i, item) { $(item).find('>a').click(); });
}
}
}
function OnCollapsibleSetCreateJQueryMobileUI(element) {
$(element).parent().parent().parent().parent().find('>h3>a').removeClass('ui-corner-bottom');
$(element).parent().find('>.ui-collapsible-content').removeClass('ui-corner-bottom');
}
function ColapseAllSiblings(parent, id) {
if (parent.Children != undefined) {
for (var i = 0; i < parent.Children.length; i++) {
if (parent.Children[i]['Id'] != id) {
if (parent.Children[i].IsExpanded != undefined && parent.Children[i].IsExpanded()) {
parent.Children[i].IsExpanded(false);
ColapseAllChildren(parent.Children[i]);
}
}
}
}
}
function ColapseAllChildren(data) {
if (data.Children != undefined) {
for (var i = 0; i < data.Children.length; i++) {
if (data.Children[i].IsExpanded != undefined && data.Children[i].IsExpanded()) {
data.Children[i].IsExpanded(false);
ColapseAllChildren(data.Children[i]);
}
}
}
}
function AttachVisibilityChangedEventHandler(options) {
var targets = options.targets ? options.targets : $(options.selector);
$.each(targets, function (i, target) {
target.addEventListener('visibilityChanged', options.eventHandler, false);
PageObj.VisibilityObserver.observe(target, { attributes: true, attributeFilter: ['class'], childList: false, attributeOldValue: true });
});
}
function VisibilityChangedEventHandler() {
var knockoutContext = ko.contextFor(this);
if (!$(this).is(':visible')){
if (knockoutContext.$parents.length > 2) {
ColapseAllChildren(knockoutContext.$data);
} else {
ColapseAllChildren(knockoutContext.$parents[0]);
}
} else {
if (knockoutContext.$parents.length > 2) {
var recordId = typeof knockoutContext.$data.Id == 'function' ? knockoutContext.$data['Id']() : knockoutContext.$data['Id'];
if (knockoutContext.$parents.length > 3) {
ColapseAllSiblings(knockoutContext.$parents[0], recordId);
} else {
ColapseAllSiblings(knockoutContext.$parents[1], recordId);
}
}
}
}
$(onTheMove.PageDataRoles).on('OnRender', function () {
$('.AppletBase >.ui-collapsible-content').attr('data-bind','visible : $parent.IsExpanded != undefined && $parent.IsExpanded()');
PageObj.VisibilityObserver = new MutationObserver(function (mutations) {
var clone = $(mutations[0].target).clone();
clone.removeClass();
for (var i = 0; i < mutations.length; i++) {
clone.addClass(mutations[i].oldValue);
}
$(document.body).append(clone);
var cloneVisibility = $(clone).is(":visible");
$(clone).remove();
if (cloneVisibility != $(mutations[0].target).is(":visible")) {
var visibilityChangedEvent = document.createEvent('Event');
visibilityChangedEvent.initEvent('visibilityChanged', false, true);
mutations[0].target.dispatchEvent(visibilityChangedEvent);
}
});
AttachVisibilityChangedEventHandler({ selector: '.ui-collapsible-content', eventHandler: VisibilityChangedEventHandler });
});
function TreeNodeClosedEventHandler(e) {
ColapseAllChildren(ko.contextFor(e.target).$data);
}
这一切都适用于所有主要浏览器的所有最新版本,因此项目继续使用这种机制。Android Browser 4
直到我们收到不支持的三星表MutationObservable
,这对我们的一位客户来说是“必须的”。
我可以用什么替代机制代替,MutationObserver
这样我就不需要重写整个事情了?或任何其他不需要完全重写的解决方案。