【问题标题】:Does knockout.js cleanNode remove all associated event listeners?knockout.js cleanNode 是否删除所有关联的事件侦听器?
【发布时间】:2017-09-14 21:03:00
【问题描述】:

我正在通过 ajax 加载页面,在每个 ajax 请求开始时我都会清理页面,然后在添加的新页面上加载 applybindings。我始终保持一个持久模型,它是更新的视图。

addEventListeners(){
    this.subscriptions.push(PubSub.subscribe('route.start',  this.removeShopView));
    this.subscriptions.push(PubSub.subscribe('route.success',  this.addShopView));
}

removeShopView(){
    ko.cleanNode(this.currentPage);
}   

addShopView(){
    this.currentPage = document.querySelector('.page-context');
    ko.applyBindings(this.model, this.currentPage);
}

我的问题是,在清理节点时,我似乎正在擦除附加到页面上我的锚链接的事件侦听器。此锚链接包含一个元素,显示我的模型中的产品计数器

<ul>
    <li><a class='nav-bag' href="/bag">Bag<span data-bind='text: counter'></span></a></li>
</ul>

我在别处设置的这个事件不再被触发,我的页面刷新而不是运行 ajax 调用。

setupLinks(){
    this.pageContextWrap.addEventListener("click", (e) => {
        this.linkClickType = undefined;
        if (e.target && e.target.nodeName.toLowerCase() == 'a') {

            if(href.indexOf(document.domain) === -1) {
                console.log("outside link");
                this.href = false;
                return;
            }

            // anchor link is local page, ajax load the href
            this.doAjaxCall();
            e.preventDefault();
            e.stopPropagation();
        }
    });
}

有没有更好的方法来解决这个问题?清理节点是否会删除所有关联的事件侦听器?

【问题讨论】:

  • 你不应该使用cleanNode。您可以将整个应用程序放入 Knockout,将 Ajax HTML 转换为 template 节点,并在 the template binding 中使用它们。
  • 我了解 cleanNode 实际上是由 Knockout 内部使用的,最好模板部分重新渲染代码。关于 Stackoverflow 的 cleanNode 讨论实际上让我误入歧途,直到我找到 stackoverflow.com/questions/15063794/…。在我的例子中,一个 ajax 调用会加载一个新页面,它会替换旧页面。您是否建议我在每次 ajax 调用后使用 ko.applyBindings 将未更改的数据模型绑定到新视图,并在页面的每个部分(例如购物篮)进行模板化?
  • 您使用applyBindings 适合您需要做的事情。我不确定最干净/最淘汰赛的做法是什么,但我正在考虑。

标签: javascript knockout.js


【解决方案1】:

首先,如您所见,you should not use cleanNode

其次,您应该更愿意让 Knockout 管理整个 DOM,而不是其中的一部分。在您的情况下,您正在以老式的自己操作 DOM 的方式处理应用程序,并使用 Knockout 管理不断变化的内容。

您真正需要的只是将绑定应用于其内容的html binding 版本。使用applyBindingsToDescendants 的简单自定义绑定处理程序可以完成这项工作。示例:

ko.bindingHandlers.boundHtml = {
    update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
        const contentHtml = ko.unwrap(valueAccessor());
        
        element.innerHTML = contentHtml;
        ko.applyBindingsToDescendants(bindingContext, element)
    }
};

const someContents = [
'First content <span data-bind="text:someValue"></span>',
'Second content <span data-bind="text:anotherValue"></span>',
'Third content <span data-bind="text:someValue() + anotherValue()"></span>'
]

ko.applyBindings({
  pageContent: ko.observable('hi there'),
  someValue: ko.observable(3),
  anotherValue: ko.observable('foo'),
  changePage() {
    if (someContents.length) {
      this.pageContent(someContents.shift());
    }
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<div data-bind="boundHtml:pageContent"></div>
<button data-bind="click:changePage">Change</button>

【讨论】:

  • 谢谢 Roy,我已经组装了一个模拟 ajax 页面加载的小提琴,我觉得它快到了。为了简单起见,我实际上是在尝试在每次加载新页面时维护购物袋计数器。它在第一次加载时将其设置为 1,但我还没有设法得到这个来更新第二个或第三个页面加载的视图jsfiddle.net/j2is/zcnxnL85/7
  • 你还在做 some-jQuery-some-Knockout 的事情。建模一切。根据需要更新模型。见jsfiddle.net/ezyLn828/1
  • 啊,现在完全有道理了,对不起 jQuery 污染
猜你喜欢
  • 2018-06-29
  • 1970-01-01
  • 1970-01-01
  • 2018-09-04
  • 2013-10-28
  • 1970-01-01
  • 1970-01-01
  • 2022-08-03
  • 2011-08-27
相关资源
最近更新 更多