【问题标题】:Replace container element when using Knockout component使用 Knockout 组件时替换容器元素
【发布时间】:2015-02-06 15:53:35
【问题描述】:

有没有办法配置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,这个功能似乎内置在模板引擎中,我假设在渲染组件模板时也会使用它。

有没有办法指定组件应该使用renderModereplaceNode 呈现?

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

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

但我真的不喜欢这种语法 - 在评论中编写真正的代码感觉像是一种肮脏、肮脏的 hack。

【问题讨论】:

  • 听起来Rendering a named template 就是您要找的东西。一般而言,Web 组件是一个 DOM 节点,它是子节点的影子。它不打算被替换,因为在这种情况下这个概念本身就被破坏了。

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


【解决方案1】:

考虑到库的性质(我说过)以及开发人员的团队理念,我想可以为缺少此选项辩护:

Knockout 是一个库,与其他 MVC 不同,它不会强制您使用框架定义的方式来构建应用程序。如果您将 Knockout 中的模板引擎与几乎所有其他 JS 模板引擎(Angular、下划线、mustache 等)相比,Knockout 是唯一一个不“修改”原生 HTML5 渲染的引擎。所有其他人都使用自定义标签,无论是&lt;% %&gt; 还是{{ }},它都需要一个小型 JS 解析器来将标签转换为有意义的东西(现在 KO 也有一个包含小胡子样式标签的 Knockout punches 插件,并且公认 KO对&lt;!-- ko --&gt; cmets 有一点“罪过”)。 KO 改为使用 HTML 5 自定义元素、注释和属性标签,完全 "vanilla"

例如,使用了 JS/DOM 类型的“对象(和现实生活?)层次结构”:只有父母才能对他们的孩子行使权力,因此绑定到的元素不会被替换,但随着孩子的扩大。举例说明:

// 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);

随后,与 KO 进行数据绑定的首选方式(通过 foreach 绑定很好地说明)是:

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

之前的 sn-p 是 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 数据(如果有人构建了一个在 HTML 中显示数据绑定缩进级别(使用withforeach)的工具,将会很有趣但是,在某些情况下,您需要注释标签,以免破坏 HTML 的布局或 css 规则(嵌套),例如要注入的“纯文本”组件 (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 -->

还有custom tags,它们是标准化的,而且清晰得多;但不幸的是,还没有 100% 准备好。首先选择data-bind,第二个选择&lt;!-- ko --&gt;,第三个选择&lt;custom&gt;(如果完全实施,会更高)。反正我是这么看的。至于您的具体情况,如果您的组件包含列表模型,您可以这样做:

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

并在你的虚拟机中包含tbody,否则如果它是一个列表项模型,你可以使用三种“语法”中的任何一种,例如注释语法

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

或者将您的组件与嵌套在特定父级(表)中的要求完全解耦,遵循SOC principle,例如:

<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>

按优先顺序..

【讨论】:

    【解决方案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>
    

    【讨论】:

      【解决方案3】:

      您可以使用评论标签:

      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 -->
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-07-16
        • 1970-01-01
        • 2017-12-22
        • 2016-02-02
        • 2014-03-04
        • 2013-03-02
        • 1970-01-01
        相关资源
        最近更新 更多