淘汰赛,绑定名称可以是动态的(变量)吗?

时间:2019-01-11 14:16:39

标签: knockout.js

如敲除官方文档所述(The data-bind syntax),绑定具有名称

<span data-bind="name: value"></span>

?可以使用变量动态设置 name 部分吗? eval在这里不起作用。

背景: 我有一堆属性,可以是常规文本,URL,电话号码,isbn等。我还为其中一些属性定制了绑定,因此我需要为每个应用最适合的绑定...以编程方式

//viewmodel props
this.url1 = ko.observable(...);
this.text1 =  ko.observable(...);
this.isbn1 = ko.observable(...);
...

var metaProps = [   
  { name: 'url1', binding: 'url' },
  { name: 'text1', binding: 'text' },
  { name: 'isbn1', binding: 'isbn' },
...
]

这里的关键是我的viewmodel的道具取决于模型对象的特定子类型,因此我不想为每个子类型(太多)实现自定义HTML模板。现在,我的模板如下:

//HTML      
<div data-bind='foreach: { data: metaProps }'>
  <!-- ko if: binding == 'url' -->  
    <span data-bind="url: $parent[name]">   
  <!-- /ko -->                                   
  <!-- ko if: binding == 'isbn' --> 
    <span data-bind="isbn: $parent[name]">  
  <!-- /ko -->              
  <!-- ko if: binding == 'text' --> 
    <span data-bind="text: $parent[name]">  
  <!-- /ko -->  
  ...
</div>

我的目标是将html简化为:

<div data-bind='foreach: { data: metaProps }'> 
    <span data-bind="binding: $parent[name]">     
</div>

3 个答案:

答案 0 :(得分:3)

有一个(很少有文档证明)实用程序功能applyBindingsToNode,它允许您创建一个自定义绑定,该绑定可能会执行您想要的操作:

ko.bindingHandlers.dynamicBinding = {
    update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
        var bindings = {};
        var bindingData = valueAccessor();
        bindings[bindingData['binding']] = bindingContext.$data[bindingData['name']];
        ko.applyBindingsToNode(element, bindings, bindingContext);
    }
};

并这样称呼它:

<div data-bind="foreach: { data: metaProps, as: 'metaProp' }">
    <span data-bind="dynamicBinding: metaProp"></span>
</div>

编辑:

我喜欢@Tomalak所建议的组件概念,因为它允许标记的更大灵活性。一个小例子来演示:

要注册组件:

ko.components.register('isbn', {
    viewModel: function(params) {
        this.content = params.content;
    },
    template: '<span data-bind="text: content"></span>'
});

ko.components.register('url', {
    viewModel: function(params) {
        this.content = params.content;
    },
    template: '<a data-bind="attr: { href: content }, text: content"></a>'
});

稍微编辑您的metaProps对象,以便命名更清晰:

var metaProps = [   
  { content: this.url1, component: 'url' },
  { content: this.text1, component: 'text' },
  { content: this.isbn1, component: 'isbn' },
...
]

然后调用component绑定以加载组件。

<div data-bind="foreach: { data: metaProps, as: 'metaProp' }">
    <!-- ko component: { name: metaProp.component, params: { content: metaProp.content } } -->
    <!-- /ko -->
</div>

答案 1 :(得分:3)

我会与templates合作,因为:

  • 在格式和数据处理方面,它提供了更大的灵活性:您不会被锁定为所有项目都使用相同的<span>,每个模板都可以不同。
  • 这是可重用的,即您可以在视图的任何位置一致地渲染isbn。它甚至可以完全取代对ISBN的自定义绑定处理程序的需求。
  • 这将产生干净直接的视图和模型。

// as a mockup of your real "isbn" handler let's just use "text"
ko.bindingHandlers.isbn = ko.bindingHandlers.text;

ko.applyBindings({
  metaProps: [
    {type: 'text', value: 'Some sample text'},
    {type: 'isbn', value: '978-1491914311'},
    {type: 'url', value: 'https://knockoutjs.com/documentation/introduction.html', text: 'Knockout Docs'}
  ]
});
.isbn {font-family: monospace;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>

<div data-bind="foreach: metaProps">
  <div data-bind="template: 'template-' + type"></div>
</div>

<script type="text/html" id="template-text">
  <span data-bind="text: value"></span>
</script>
<script type="text/html" id="template-isbn">
  <span class="isbn" data-bind="isbn: value"></span>
</script>
<script type="text/html" id="template-url">
  <a data-bind="attr: {href: value}, text: text"></a>
</script>

如果您更喜欢components,那是另一种选择。

答案 2 :(得分:0)

不确定这是否可以解决您的完整问题,但可以动态生成html。

function VM(){

var self = this;
self.metaProps = [   
  { name: 'url1', val: '<a href="https://google.com">url</a>' },
  { name: 'text1', val: 'text' },
  { name: 'isbn1', val: 'isbn' },
]

}
ko.applyBindings(new VM());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div data-bind="foreach:metaProps"> 
    <span data-bind="html:val"><br/>     
</div>