使用 Knockout 组件时替换容器元素 [英] Replace container element when using Knockout component

查看:17
本文介绍了使用 Knockout 组件时替换容器元素的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

<p>你好世界!</p></tr>

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

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

最终产品是这样的:

<tr><p>你好世界!</p></tr></tbody>

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

<我的自定义元素><tr><p>你好世界!</p></tr></my-custom-element></tbody>

基于这个问题的答案,看来这个功能是内置在模板引擎中的,我'm 假设也用于渲染组件模板.

有没有办法指定一个组件应该用 replaceNoderenderMode 渲染?

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

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

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

解决方案

考虑到库的性质(在那里,我说过)和开发人员的团队理念,我认为可以为缺少此选项进行辩护:

Knockout 是一个库,与其他 MVC 不同,它不会强制您使用框架定义的方式来构建应用程序.如果您将 Knockout 中的模板引擎与几乎所有其他 JS 模板引擎(Angular、下划线、mustache 等)相比,Knockout 是唯一一个不修改"原生 HTML5 渲染的引擎.所有其他人都使用自定义标签,无论是 <% %> 还是 {{ }} 这都需要一个小的 JS 解析器来将标签转换成有意义的东西(现在 KO还有一个 Knockout Punches 插件,其中包含小胡子风格的标签,无可否认,KO 确实犯了罪" 注释).KO 使用 HTML 5 自定义元素、注释和属性标签,完全原版".

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

//我们不能在 JS 中做到这一点document.getElementById('elem').remove();//隐含的 .remove(self)//相反,我们这样做var elem = document.getElementById('elem');容器 = elem.parentNode.removeChild(elem);

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

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

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

var myArr = [1,2,3,4,5];//我们不能在不参考数组索引的情况下执行以下操作,//不由对象本身持有,//但是一个元属性相对于父属性获得意义myArr[0].splice(0,1);//消除

这会导致您的 HTML 视图完美地复制您的 JS 数据(看到有人构建了一个工具来显示数据绑定缩进级别(使用 withforeach) 在 HTML 文档中.但是,在某些情况下,您需要注释标签,以免破坏 HTML 的布局或 css 规则(嵌套),例如纯文本"' 要在文本节点之间注入的组件 (i18n):

<p>一些带有<!-- ko text: 'some variable text' --><!--/ko -->以及更多预定义文本

或者当你不希望一个空元素在隐藏时占用空间

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

然后是自定义标签,这些是标准化的,而且更加清晰;但不幸的是还没有 100% 准备好.首先选择 data-bind 第二, 第三(如果全面实施).反正我是这么看的.至于你的具体情况,如果你的组件拥有一个列表模型,你可以这样做:

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

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

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

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

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

或使用自定义标签:

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

按照优先顺序..

Is there a way to configure a Knockout component to replace the container element instead of nesting its content inside the container element?

For example, if I have a custom component registered as my-custom-element with the following template:

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

Is it possible to use the component like this:

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

And have the final product be this:

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

Instead of this: (the way Knockout renders components by default)

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

Based on the answer to this question, it seems that this functionality is built into the templating engine, which I'm assuming is also used when rendering component templates.

Is there a way to specify that a component should be rendered with a renderMode of replaceNode?

I'm aware of the "virtual element" syntax, which allows components to be defined inside an HTML comment:

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

but I really dislike this syntax - writing real code inside a comment feels like a dirty, dirty hack.

解决方案

I imagine the lack of this option could be defended as such, considering the nature of the library (there, I said it), and the developer's team philosophy:

Knockout is a library and unlike other MVC's it does not force you to use a framework-defined way to structure your application. If you consider the template engine in Knockout vs. virtually all other JS templating engines (in Angular, underscore, mustache, etc.), Knockout comes out as the only one not 'modding' native HTML5 rendering. All others use a custom tag, be it <% %> or {{ }} which requires a small JS parser to transform the tags into something meaningful (now KO also has a Knockout punches plugin which includes the mustache-style tags, and admittedly KO does 'sin' a small bit with <!-- ko --> comments). KO instead uses HTML 5 custom elements, comment and attribute tags, completely "vanilla".

For instance, the JS/DOM type of 'object (and real life?) hierarchy' is used: only parents can ever exerce power on their children, and so the bound-to element is not replaced, but enlarged with children. For illustration:

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

Subsequently, the preferred way of data-binding with KO, illustrated well by the foreach binding, is:

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

The previous snippet being an HTML representation of a JS array, the hierarchy is visible again:

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

This leads to your HTML view being a perfect replication of your JS data (and it would be interesting to see someone build a tool that shows the data-bind indentation levels (with with and foreach) in an HTML document. In some cases however, you need comment tags, so as to not break the lay-out of your HTML, or your css rules (nesting), for example a 'text-only' component (i18n) that is to be injected between text nodes:

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

Or when you don't want an empty element to take up space when hidden

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

And then there are custom tags, which are standardized and a hell of a lot clearer; but unfortunately not a 100% ready yet. Choose data-bind first, <!-- ko --> second, and <custom> third (would be higher if fully implemented). That's how I see it, anyway. As for your specific case, if your component holds a list model, you could do:

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

And include the tbody in your VM, else if it is a listitem model, you can use either one of the three 'syntaxes', eg the comment syntax

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

Or decouple your component completely from the requirement of being nested inside a specific parent (table), adhering to the SOC principle, eg:

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

or with a custom tag:

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

in that order of preference..

这篇关于使用 Knockout 组件时替换容器元素的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆