使用Knockout组件时替换容器元素

时间:2015-02-06 15:53:35

标签: javascript knockout.js web-component knockout-components knockout-templating

有没有办法配置Knockout component替换容器元素而不是将其内容嵌套在容器元素中?

例如,如果我使用以下模板注册为my-custom-element的自定义组件:

<tr>
    <p>Hello world!</p>
</tr>

是否可以使用这样的组件:

<table>
    <tbody>
        <my-custom-element></my-custom-element>
    </tbody>
</table>

最终产品是这样的:

<table>
    <tbody>
        <tr>
            <p>Hello world!</p>
        </tr>
    </tbody>
</table>

而不是:( Knockout默认渲染组件的方式)

<table>
    <tbody>
        <my-custom-element>
            <tr>
                <p>Hello world!</p>
            </tr>
        </my-custom-element>
    </tbody>
</table>

Based on the answer to this question,似乎这个功能内置在模板引擎中,我假设在渲染组件模板时也会使用它。

有没有办法指定应使用renderMode replaceNode来呈现组件?

我知道“虚拟元素”语法,它允许在HTML注释中定义组件:

<table>
    <tbody>
        <!--ko component { name: 'my-custom-element' }--><!--/ko-->
    </tbody>
</table>

但我真的不喜欢这种语法 - 在评论中编写真实的代码感觉就像一个肮脏,肮脏的黑客。

3 个答案:

答案 0 :(得分:4)

我认为考虑到图书馆的性质(在那里,我说过)以及开发人员的团队理念,可以捍卫这种选择的缺乏:

Knockout是一个库,与其他MVC不同,它不会强迫您使用框架定义的方式来构建应用程序。如果您考虑Knockout中的模板引擎与几乎所有其他JS模板引擎(Angular,下划线,小胡子等), Knockout是唯一一个没有&#39; modding&#39;本机HTML5呈现。所有其他人都使用自定义标记,无论是<% %>还是{{ }},需要一个小的JS解析器将标记转换为有意义的标记(现在KO也有{{3}包含小胡子风格标签的插件,不可否认,KO确实在<!-- ko -->评论中犯了一小部分内容。 KO改为使用HTML 5自定义元素,评论和属性标签,完全&#34; vanilla&#34;

例如,JS / DOM类型的&#39;对象(和现实生活?)层次结构&#39;使用:只有父母可以强行对孩子施加威胁,因此绑定元素不会被替换,而是随着孩子而扩大。例如:

// we cannot do this in JS
document.getElementById('elem').remove(); //implied .remove(self)
// instead we do this
var elem = document.getElementById('elem');
container = elem.parentNode.removeChild(elem);

随后,foreach绑定所示的与KO数据绑定的首选方式是:

<div data-bind="foreach: myList">
  <span data-bind="text: $data"></span>
</div>

前面的代码片段是JS数组的HTML表示形式,层次结构再次可见:

var myArr = [1,2,3,4,5];
// we cannot do the following without reference to the array index, 
// which is not held by the object itself,     
// but a meta-property getting meaning relative to the parent
myArr[0].splice(0,1); //remove

这会使您的HTML视图成为您JS数据的完美复制(看到有人构建一个显示数据绑定缩进级别的工具会很有趣(使用withforeach在HTML文档中。但是,在某些情况下,您需要使用注释标记,以便不破坏HTML的布局或css规则(嵌套),例如“仅文本”和#c;要在文本节点之间注入的组件(i18n):

<p>Some predefined text with
<!-- ko text: 'some variable text' --><!-- /ko -->
and more predefined text</p>

或者当你不想要一个空的元素在隐藏时占用空间

<!-- ko if: !hidden() --><div id="myToggleableDiv"></div><!-- /ko -->

然后有Knockout punches,它们是标准化的,并且更加清晰;但遗憾的是还没有100%准备好。首先选择data-bind,然后选择<!-- ko -->秒,然后选择<custom>第三(如果完全实施则会更高)。无论如何,这就是我的看法。至于您的具体情况,如果您的组件包含列表模型,您可以执行以下操作:

<table data-bind="{component: {name: 'custom', params {..}}"></table>

并在您的VM中包含tbody,否则如果它是listitem模型,您可以使用三种语法之一,例如注释语法

<table>
  <tbody data-bind="foreach: mylist">
    <!-- ko component: {name: 'custom', params: $data} --><!-- /ko -->
  </tbody>
</table>

或者将您的组件与嵌套在特定父级(表格)中的要求完全分离,并遵守custom tags,例如:

<table>
  <tbody data-bind="foreach: mylist">
    <tr data-bind="foreach: properties">
      <td data-bind="component: {name: 'custom', params: $data}></td>
    </tr>
  </tbody>
</table>

或使用自定义标记:

<table>
  <tbody data-bind="foreach: mylist">
    <tr data-bind="foreach: properties">
      <td><custom params= "{data: myData"></custom></td>
    </tr>
  </tbody>
</table>

按照优先顺序..

答案 1 :(得分:2)

好消息!在Knockout 3.3.0中,他们刚刚介绍了Passing markup into components的概念。这是通过使用组件中的$componentTemplateNodes模板完成的。

来自链接的示例:

<template id="my-special-list-template">
    <h3>Here is a special list</h3>

    <ul data-bind="foreach: { data: myItems, as: 'myItem' }">
        <li>
            <h4>Here is another one of my special items</h4>
            <!-- ko template: { nodes: $componentTemplateNodes, data: myItem } --><!-- /ko -->
        </li>
    </ul>
</template>

<my-special-list params="items: someArrayOfPeople">
    <!-- Look, I'm putting markup inside a custom element -->
    The person <em data-bind="text: name"></em>
    is <em data-bind="text: age"></em> years old.
</my-special-list>

答案 2 :(得分:0)

您可以使用评论标签:

https://knockoutjs.com/documentation/component-binding.html#note-using-component-without-a-container-element

<!-- ko component: {
    name: "message-editor",
    params: { initialText: "Hello, world!", otherParam: 123 }
} -->
<!-- /ko -->