使用 Knockout 组件时替换容器元素
Replace container element when using Knockout component
有没有办法配置 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,似乎这个功能内置于模板引擎中,我假设在渲染组件模板时也会使用它。
有没有办法指定一个组件应该用replaceNode
的renderMode
呈现?
我知道 "virtual element" 语法,它允许在 HTML 注释中定义组件:
<table>
<tbody>
<!--ko component { name: 'my-custom-element' }--><!--/ko-->
</tbody>
</table>
但我真的不喜欢这种语法——在注释中编写真正的代码感觉就像是一种肮脏、肮脏的黑客行为。
考虑到库的性质(我已经说过)和开发人员的团队理念,我认为缺少此选项可以这样辩护:
Knockout 是一个库,与其他 MVC 不同,它不会强制您使用 framework-defined 方式来构建您的应用程序。如果您将 Knockout 中的模板引擎与几乎所有其他 JS 模板引擎(在 Angular、下划线、小胡子等中)进行比较,Knockout 是唯一一个不是 'modding' 的本机 HTML5 呈现。 所有其他人都使用自定义标签,无论是 <% %>
还是 {{ }}
这需要一个小型 JS 解析器将标签转换为有意义的东西(现在 KO 也有一个 Knockout punches 插件,其中包含 mustache-style 标签,诚然 KO 做了 'sin' 一点 <!-- ko -->
评论)。 KO改为使用HTML5个自定义元素,注释和属性标签,完全"vanilla".
例如,'object (and real life?) hierarchy' 的 JS/DOM 类型被使用: 只有 parent 可以在他们的 children 上行使权力,等等bound-to 元素没有被替换,而是被 children 放大了。举例说明:
// 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);
随后,data-binding 与 KO 的首选方式,foreach
绑定很好地说明了,是:
<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 数据(看到有人构建一个显示 data-bind 缩进级别的工具会很有趣(with
和 foreach
) 在 HTML 文档中。但是在某些情况下,您需要注释标签,以免破坏 HTML 的 lay-out 或 css 规则(嵌套),例如要在文本节点之间注入的 'text-only' 组件 (i18n):
<p>Some predefined text with
<!-- ko text: 'some variable text' --><!-- /ko -->
and more predefined text</p>
或者当你不希望空元素在隐藏时占据space
<!-- ko if: !hidden() --><div id="myToggleableDiv"></div><!-- /ko -->
然后是 custom tags,它们是标准化的,而且非常清晰;但不幸的是还没有 100% 准备好。首先选择 data-bind
,然后选择 <!-- ko -->
,然后选择 <custom>
第三(如果完全实施会更高)。无论如何,这就是我的看法。至于你的具体情况,如果你的组件拥有一个列表模型,你可以这样做:
<table data-bind="{component: {name: 'custom', params {..}}"></table>
并在您的 VM 中包含 tbody
,否则如果它是一个列表项模型,您可以使用三个 'syntaxes' 中的任何一个,例如注释语法
<table>
<tbody data-bind="foreach: mylist">
<!-- ko component: {name: 'custom', params: $data} --><!-- /ko -->
</tbody>
</table>
或者将您的组件完全从嵌套在特定 parent (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>
按照优先顺序..
好消息!在 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>
您可以使用评论标签:
<!-- ko component: {
name: "message-editor",
params: { initialText: "Hello, world!", otherParam: 123 }
} -->
<!-- /ko -->
有没有办法配置 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,似乎这个功能内置于模板引擎中,我假设在渲染组件模板时也会使用它。
有没有办法指定一个组件应该用replaceNode
的renderMode
呈现?
我知道 "virtual element" 语法,它允许在 HTML 注释中定义组件:
<table>
<tbody>
<!--ko component { name: 'my-custom-element' }--><!--/ko-->
</tbody>
</table>
但我真的不喜欢这种语法——在注释中编写真正的代码感觉就像是一种肮脏、肮脏的黑客行为。
考虑到库的性质(我已经说过)和开发人员的团队理念,我认为缺少此选项可以这样辩护:
Knockout 是一个库,与其他 MVC 不同,它不会强制您使用 framework-defined 方式来构建您的应用程序。如果您将 Knockout 中的模板引擎与几乎所有其他 JS 模板引擎(在 Angular、下划线、小胡子等中)进行比较,Knockout 是唯一一个不是 'modding' 的本机 HTML5 呈现。 所有其他人都使用自定义标签,无论是 <% %>
还是 {{ }}
这需要一个小型 JS 解析器将标签转换为有意义的东西(现在 KO 也有一个 Knockout punches 插件,其中包含 mustache-style 标签,诚然 KO 做了 'sin' 一点 <!-- ko -->
评论)。 KO改为使用HTML5个自定义元素,注释和属性标签,完全"vanilla".
例如,'object (and real life?) hierarchy' 的 JS/DOM 类型被使用: 只有 parent 可以在他们的 children 上行使权力,等等bound-to 元素没有被替换,而是被 children 放大了。举例说明:
// 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);
随后,data-binding 与 KO 的首选方式,foreach
绑定很好地说明了,是:
<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 数据(看到有人构建一个显示 data-bind 缩进级别的工具会很有趣(with
和 foreach
) 在 HTML 文档中。但是在某些情况下,您需要注释标签,以免破坏 HTML 的 lay-out 或 css 规则(嵌套),例如要在文本节点之间注入的 'text-only' 组件 (i18n):
<p>Some predefined text with
<!-- ko text: 'some variable text' --><!-- /ko -->
and more predefined text</p>
或者当你不希望空元素在隐藏时占据space
<!-- ko if: !hidden() --><div id="myToggleableDiv"></div><!-- /ko -->
然后是 custom tags,它们是标准化的,而且非常清晰;但不幸的是还没有 100% 准备好。首先选择 data-bind
,然后选择 <!-- ko -->
,然后选择 <custom>
第三(如果完全实施会更高)。无论如何,这就是我的看法。至于你的具体情况,如果你的组件拥有一个列表模型,你可以这样做:
<table data-bind="{component: {name: 'custom', params {..}}"></table>
并在您的 VM 中包含 tbody
,否则如果它是一个列表项模型,您可以使用三个 'syntaxes' 中的任何一个,例如注释语法
<table>
<tbody data-bind="foreach: mylist">
<!-- ko component: {name: 'custom', params: $data} --><!-- /ko -->
</tbody>
</table>
或者将您的组件完全从嵌套在特定 parent (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>
按照优先顺序..
好消息!在 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>
您可以使用评论标签:
<!-- ko component: {
name: "message-editor",
params: { initialText: "Hello, world!", otherParam: 123 }
} -->
<!-- /ko -->