【问题标题】:Knockout, ¿could the binding name be dynamic (a variable)?淘汰赛,¿绑定名称可以是动态的(变量)吗?
【发布时间】:2019-01-11 14:16:38
【问题描述】:

正如淘汰赛官方文档所说 (The data-bind syntax),绑定具有 namevalue

<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' },
...
]

这里的关键是我的视图模型的道具取决于模型对象的特定子类型,所以我不想为每个子类型(太多)实现自定义 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>

【问题讨论】:

    标签: knockout.js


    【解决方案1】:

    我会与templates 合作,因为:

    • 它在格式化和数据处理方面提供了更大的灵活性:您不必为所有项目使用相同的&lt;span&gt;,每个模板都可以不同。
    • 它是可重复使用的,即您可以在视图中的任何位置一致地渲染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】:

      有一个(遗憾的是未记录)实用函数 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>
      

      【讨论】:

        【解决方案3】:

        不确定这是否可以解决您的全部问题,但您可以动态生成 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>

        【讨论】:

          猜你喜欢
          • 2013-01-09
          • 2013-03-06
          • 2014-01-17
          • 1970-01-01
          • 2014-12-08
          • 2013-11-22
          • 2013-02-04
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多