我正在使用JQuery mobile expandable list
和Knockout.js
组合的网页。我编写的机制允许构建ViewModel树结构并将其绑定到可扩展列表。由于某些treenode可能很大,我使用了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
的{{1}}提交的三星,这是一个必须&#39;}我们的一位客户。
我可以采用什么替代机制代替MutationObservable
所以我不需要重写整个事情?或任何其他不需要完全重写的解决方案。