【问题标题】:How to get the binding expression inside a BindingHandler in Knockout JS如何在 Knockout JS 的 BindingHandler 中获取绑定表达式
【发布时间】:2012-12-30 10:25:32
【问题描述】:

假设我有一个绑定跨度

<span data-bind="MyBinding: Name"></span>

我有一个自定义绑定

ko.bindingHandlers.MyBinding = {
   init: function (element, valueAccessor, allBindings, viewModel, context) {
        // I want to get the string "Name" here. NOT the value of Name.
   },
};

如何在处理程序中获取包含绑定表达式值的字符串?即我如何获得“名称”而不是“名称的价值”。

我还需要表达式,因此传递字符串“Name”是不可行的。

<span data-bind="MyBinding: 'Name'"></span>

【问题讨论】:

    标签: javascript data-binding knockout.js


    【解决方案1】:

    实际上,Knockout确实有一个内置的方法来做到这一点。您确实需要稍微调整您的自定义绑定(即,它变成一个对象而不是字符串值)。 Knockout 允许您与initupdate 属性一起指定preprocess 属性。例如,假设我们有以下 viewModel:

    var app = { data: ko.observable('Hello World') };
    

    还有一个简单的绑定,它将传递给它的字符串完全转换为小写,并输出绑定的名称和值(视图中传递的属性显然是data):

    ko.bindingHandlers.lower = {
      update: function(elem, value) {
        var obj = ko.unwrap(value());
        elem.textContent = 'Name: ' + ko.unwrap(obj.name) + 
          ' - Value: ' + ko.unwrap(obj.data).toLowerCase();
      },
      preprocess: function(value, bindingName) {
        return '{data:' + value + ', name:\'' + bindingName + '\'}';
      }
    };
    

    就像将传递给它的value 属性字符串化并将绑定的值转换为具有2 个键(此处为名称和值)的对象一样简单。 Have a look。请参阅Binding preprocessing 了解更多信息。

    【讨论】:

      【解决方案2】:

      您需要将Name 作为字符串而不是作为参考传递:

      <span data-bind="MyBinding: 'Name'"></span>
      
      ko.bindingHandlers.MyBinding = {
         init: function (element, valueAccessor, allBindings, viewModel, context) {
              var myBinding = valueAccessor(); // will contain 'Name';
              var valueOfmyBinding = viewModel[myBinding]; //value of the Name property
         },
      };
      

      您仍然可以将表达式用作字符串,因为在 Javascript 中您可以使用 eval 尽管 eval() 是一个危险函数:这是一个示例 JSFiddle

      或者,如果您只需要支持像Child.Name 这样的简单属性表达式,您可以编写自己的解析器,在其中将字符串拆分为点,并在访问器上进行 foreach。

      【讨论】:

      • 如果它是一个复杂的表达式,它将如何工作。例如“Child.Name”
      • 为什么字符串不适合你?在 JavaScript 中,您可以将 eval 基本上任何字符串转换为 JS 代码。
      • 或者如果你有像Child.Name这样的基本表达式,你可以编写自己的解析器。只需在访问器上的点和 foreach 上拆分。
      • @Simon 一个带有 eval jsfiddle.net/Z9Yvu 的小样本。很难,我会​​选择自定义解析,因为 eval 可能非常危险。
      • 是否仍然没有本地方法可以做到这一点,而无需调用 viewModelbindingContext.$data[]。我也在做同样的事情,幸好我只需要简单的表达方式。
      【解决方案3】:

      您可以执行以下操作,因此您不需要 eval。

      <span data-bind="MyBinding: 'Name.More.AndMore'"></span>
      
      ko.bindingHandlers.MyBinding = {
          init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
              var value = valueAccessor();
      
              var sp = value.split('.');
              var current = viewModel;
              for(var i=0;i<sp.length;i++) {
                  var nNode = current[sp[i]];
                  if ( nNode ) {
                      current = nNode;
                  }
              }
              $(element).html(current());
          }
      };
      

      正如 已经解释的那样,您需要在绑定中将名称作为字符串值提供。之后,您可以使用它来逐步浏览您的视图模型以检索值。在我添加的元素中显示值 $(element).html(current()); 这里current() 在我的视图模型中处于最深层次,因此可以调用它,并且可以使用返回值来更新 html。

      【讨论】:

      • 你能描述一下“以下”是什么吗?为什么它会回答这个问题?你可以edit你的答案包括一个描述。
      • 我刚刚扩展了@nemesv 给出的答案。下面我的意思是下面的一段代码
      【解决方案4】:

      我建议使用另一个绑定来转移属性的名称。

      <div data-bind="myBinding: content, nameOfProp:'content'"></div>
      
      ko.bindingHandlers.myBinding = {
          init: function(element, valueAccessor, allBindings, viewModel, context) {
            var nameOfProp = allBindings.get("nameOfProp");
          };
        }
      

      JSFiddle

      【讨论】:

        【解决方案5】:

        我喜欢上面说的pavel-chervov。如果您不介意使用一点 jQuery,则类似地:

        <span data-binding-name="Name" data-bind="MyBinding: Name"></span>
        
        ko.bindingHandlers.MyBinding = {
            init: function (element, valueAccessor, allBindings, viewModel, context) {
                var nameOfProp = $(element).data('binding-name');
            },
        };
        

        【讨论】:

          【解决方案6】:

          我参加聚会有点晚了,但这就是我所做的,它就像一个魅力:

          JS:

          ko.bindingHandlers.myHandler = {
              init: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
                  var regex = /return ([^\s]+)\s*}/;
          
                  //accessor will contain whatever expression was used in data-bind
                  //so in this example it will be "myProp.childProp"
                  var accessor = regex.exec(valueAccessor.toString())[1];
          
                  //...
          },
          //...
          

          HTML:

          <div data-bind="myHandler: myProp.childProp"></div>
          

          所以访问器的值(如果你错过了评论)将是“myProp.childProp”

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2018-01-09
            • 1970-01-01
            • 2017-06-19
            • 2012-10-20
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-10-19
            相关资源
            最近更新 更多