淘汰组件(不)绑定到新内容

Posted

技术标签:

【中文标题】淘汰组件(不)绑定到新内容【英文标题】:Knockout components (not) binding on new content 【发布时间】:2015-01-24 02:42:41 【问题描述】:

编辑的问题和示例

我试图让 Knockout 组件在初始 ko.applyBindings(); 之后绑定,以便我可以动态添加自定义元素。

在我的原始帖子中,我提到了通过 ajax 加载内容,但是当使用 jQuery append 之类的东西将自定义元素添加到 DOM 时,就会出现问题。

这是一个例子:

$(function() 

  // Register a simple widget:
  ko.components.register('like-widget', 
    template: '<div class="alert alert-info">This is the widget</div>'
  );

  // Apply bindings
  ko.applyBindings();


  // Wire up 'add' button:
  $('#btnAdd').on('click', function() 

    $('#addZone').append("<like-widget></like-widget>");


  );

);
<link data-require="bootstrap-css@*" data-semver="3.2.0" rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>

<body>

  Here's a widget, declared inline:
  <like-widget></like-widget>

  <button id='btnAdd'>Add a new widget to the grey box:</button>
  <br/><br/>

  <div id='addZone' class="well">
    Widgets will be appended here
  </div>

  <p>When you run this code, the widget custom element is indeed added to the box (see source) but the widget's template is not bound, so nothing appears. How do I get it to bind/appear?</p>


</body>

原帖

我已经成功创建了我的新组件&lt;mynew-widget&gt;&lt;/mynew-widget&gt;

我已经看到了在我的页面上添加它们的乐趣,并且一切都运行良好......直到我加载包含&lt;mynew-widget&gt;&lt;/mynew-widget&gt; 的新内容(例如,加载 AJAX 的模式弹出窗口)。什么都没有发生。

这是 Knockout 的限制还是我接线错误?

请告诉我是后者 - 因为我喜欢不必担心何时/在何处调用 ApplyBindings 以及在 DOM 的哪些部分。

经过深思熟虑,我知道淘汰赛需要注意自定义元素已添加到 DOM 中 - 但我希望它可能只是以 jQuery '$().on(...)' 之类的方式工作。

【问题讨论】:

您需要包含您正在尝试做的事情的代码示例。照原样,我们无法帮助您调试 以上+你可能没有正确接线 好的 - 已编辑和重新调整。另外 - 我知道你可能想用 KO 本身实现 btnAdd 功能,但我只想说我不想允许完全的灵活性。 【参考方案1】:

组件绑定不会神奇地发生:它会在您调用ko.applyBindings(); 时发生。此时,在绑定的 html 中搜索组件,并绑定。

稍后,当您向页面动态添加新组件时,它不会被绑定,除非您显式绑定它。因此,在您的代码中,该组件被完全忽略。

如上所述,您需要做的是显式绑定它。但是必须考虑到不能绑定已经绑定的节点。但是,使用 jquery 创建节点、将其附加到 DOM 并绑定它非常容易。有一种语法可以指定视图模型和要绑定它的节点:ko.applyBindings(viewModel, node);

Here you have a full working sample in jsfiddle。这是那个小提琴中的代码:

HTML:

这是一个小部件,声明为内联:

  <button id='btnAdd'>Add a new widget to the grey box:</button>
  <br/><br/>

  <div id='addZone' class="well">
    Widgets will be appended here
  </div>

javascript

ko.components.register('like-widget', 
    template: '<div class="alert alert-info">This is the widget</div>'
  );

ko.applyBindings()

$('#btnAdd').on('click', function() 
   // Create your widget node
   var $newWidget = $('<like-widget>');
   // Append it to your "append area"
   $('#addZone').append($newWidget);
   // Apply bindings to the newly added node
   ko.applyBindings(, $newWidget[0]);
);

注意:当调用应用绑定时,我传递了一个空对象:不要传递空值,否则会出错。如果您的模板包含视图模型,它将独立于传递的视图模型使用。

注意:$newWidget 是一个 jquery 对象。 $newWidget[0] 是 jQuery 对象的第一个(也是唯一一个)DOM 元素,如 applyBindings 所要求的

【讨论】:

好的,谢谢,这个很清楚了。您是否认为有可能以某种方式将其包装起来,以便开发人员可以仅在 HTML 中以万无一失的方式添加这些组件?例如,通过观察整体 DOM 突变并触发 applyBindings()? 可以观察到 HTML 突变 (***.com/questions/2844565/…)。但是你必须小心我上面解释的一些事情:你不能在同一个元素上应用两次绑定。这包括不对已绑定元素的子元素应用绑定。但是,当您动态添加项目时,您似乎没有这个问题。请尝试一下,如果你遇到这个问题,请告诉我。有一种技术可以避免元素及其子项绑定。

以上是关于淘汰组件(不)绑定到新内容的主要内容,如果未能解决你的问题,请参考以下文章

使用 jQuery-ui 对话框的 Knockout 组件忽略绑定

将 vue js 应用程序绑定到 django 模板不显示任何内容

组件:使用slot进行内容分发

当页面通过ajax作为部分加载时,如何重新绑定淘汰视图模型?

Angular DomSanitizer 不绑定角度组件

weex 数据绑定,动态控制组件的显示内容及样式