0

我正在使用JQuery mobile expandable listKnockout.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这样我就不需要重写整个事情了?或任何其他不需要完全重写的解决方案。

4

0 回答 0