将文本绑定到全局函数

Bind text to a global function

尝试将 text 绑定到视图模型外部的全局函数会引发以下错误:

knockout.js:60 Uncaught ReferenceError: Unable to process binding "foreach: function (){return names }" Message: Unable to process binding "text: function (){return myFunction($data) }" Message: myFunction is not defined

Reproduction online

HTML

<ul data-bind="foreach: names">
    <li data-bind="text: myFunction($data)"></li>
</ul>

JS

function myFunction(text){
    return text + '--';
}

function demoViewModel() {
    self.names = ['a', 'b', 'c'];

    return self;
}

var mm = new demoViewModel();

ko.applyBindings(mm);

相反,如果我扩展 String 对象并按以下方式应用函数,它会按预期工作:

<li data-bind="text: $data.myFunction()"></li>

扩展字符串对象:

String.prototype.myFunction = function(){
    return this + '--';
}

Reproduction online

这是为什么?没有更好的方法将全局函数应用于 text 绑定吗?

这是我的建议,您可以按照自己的意愿行事。您的函数未在该范围内定义。在这里,您实际上将每个名称(即使它可以是一个对象)绑定到视图模型之外的函数
示例:https://jsfiddle.net/1hz10pkc/2/
HTML :

<ul data-bind="foreach: names">
    <li data-bind="text:name "></li>
</ul> 

JS

var myFunction = function(text){
  var self = this;
  self.name = text + "--" ; 
}

function demoViewModel() {
   var self = this;
   var arr =  ['a', 'b', 'c'];
   self.names = ko.observableArray($.map(arr, function (element) {
        return new myFunction(element);
    }));
}
var mm = new demoViewModel();

ko.applyBindings(mm);

要从挖空模板中引用您的函数,需要将其附加到 ViewModel。在上面的简单情况下,您可以将它附加到 demoViewModel 并直接在您的模板中引用它:

function myFunction(text){
    return text + '--';
}

function demoViewModel() {
    var self = this;
    self.names = ['a', 'b', 'c'];
    self.myFunction = myFunction;

    return self;
}

ko.applyBindings(new demoViewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<ul data-bind="foreach: names">
    <li data-bind="text: myFunction($data)"></li>
</ul>

这并不是一个真正的 "global" 函数,它只是一个标准的 viewModel 属性,如果你最终得到了嵌套的绑定上下文,你必须做 $parents[n].myFunction 或者,如果你已经将它附加到你的根 viewModel,你可以做 $root.myFunction.


另一种处理方法是直接将函数添加到 binding context。这允许无论当前 viewModel 是什么都可以引用它。

"foreach" 绑定处理程序和模板绑定处理程序的 "as" 选项是一种向绑定上下文添加内容的方法;但是我为此目的使用了 "let" bindingHandler,let bindingHandler 不是 KO 的官方部分,而是 often recommended Michael Best 的核心贡献者之一。

function myFunction(text){
    return text + '--';
}

function demoViewModel() {
    var self = this;
    self.names = ['a', 'b', 'c'];
    self.myFunction = myFunction;

    return self;
}


//Let binding Handler
ko.bindingHandlers['let'] = {
    'init': function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        // Make a modified binding context, with extra properties, and apply it to descendant elements
        var innerContext = bindingContext.extend(valueAccessor());
        ko.applyBindingsToDescendants(innerContext, element);

        return { controlsDescendantBindings: true };
    }
};
ko.virtualElements.allowedBindings['let'] = true;

ko.applyBindings(new demoViewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>

<!-- ko let: {
    myFunction: myFunction
} -->
  <ul data-bind="foreach: {
      data: names,
      at: 'name'
  }">
      <li data-bind="text: myFunction($data)"></li>
  </ul>
<!-- /ko -->

在上面的示例中,您可以在 let 绑定中的任何位置引用 myFunction,无论您的 viewModels 有多深。