Knockout高级声明javascript"与" -like

时间:2014-11-03 17:48:26

标签: javascript knockout.js

我陷入了需要在子元素中随处可见的自定义变量的区域,例如我们可以引用的$ parents,$ parent。 例如:

<div data-bind:"addThisVariable: { name: '$hello', value: somethingTimeConsuming() }">
     <div data-bind="foreach: something">
         <span data-bind="text: $hello.stringReference">                 
         </span>
     </div>
</div>

我想知道它是否已经与Knockout一起提供,或者是否有人知道如何实现这一目标。

我想用一个像“$ something”这样的变量来填充上下文及其子上下文

但是在淘汰赛中,对于我声明的所有情境和儿童情境。 所以我可以完成潜在的耗时任务,而不必每次都重新运行它们。

编辑:我不希望“with:$ something”绑定不能回答我的答案

它就像一个临时变量,我需要填充子上下文,就像我们为

做的那样
.forEach(function(item){
    var somethingCalculated = 1234;
    item.someArray.forEach(function(subItem) {
        var somethingElse = somethingCalculated + 567;
    }
})

3 个答案:

答案 0 :(得分:3)

前段时间,我为自己创建了一个名为let的简单绑定,可以完成您想要的操作。这是:

ko.bindingHandlers['let'] = {
    init: function(element, valueAccessor, allBindings, 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;

您可以这样使用它:

<div data-bind:"let: { $hello: somethingTimeConsuming() }">
     <div data-bind="foreach: something">
         <span data-bind="text: $hello.stringReference">                 
         </span>
     </div>
</div>

ko.bindingHandlers['let'] = {
    init: function(element, valueAccessor, allBindings, 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;

(function() {
    var vm = {
        foo: ko.observable("foo"),
        bar: ko.observable("bar"),
        list: ko.observableArray([
            'one', 'two', 'three'
        ])
    };
    vm.hello = ko.pureComputed(function() {
        return vm.foo() + vm.bar();
    });

    ko.applyBindings(vm);
})();
<script src="//cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<div data-bind="let: { $hello: hello() }">
    <div data-bind="foreach: list">
        <span data-bind="text: $data"></span><span data-bind="text: $hello"></span>
    </div>
</div>

答案 1 :(得分:2)

这两个选项都没有给你JavaScript with(但是,JavaScript的with有一些非常重要的维护问题),但这里有几个选项:


您最好的选择可能是(比如说)容器甚至是根VM。

yourVm.hello = ko.computed({
    pure: true, // If it is, that is
    read: function() {
        // complex stuff here
    }
});

示例:

(function() {
  "use strict";

  var vm = {
    foo: ko.observable("foo"),
    bar: ko.observable("bar"),
    list: ko.observableArray([
      'one', 'two', 'three'
    ])
  };
  vm.hello = ko.computed({
    pure: true,
    owner: this,
    read: function() {
      return this.foo() + this.bar();
    }
  });

  ko.applyBindings(vm, document.body);
})();
<script src="//cdnjs.cloudflare.com/ajax/libs/knockout/3.1.0/knockout-min.js"></script>
<div data-bind="foreach: list">
  <span data-bind="text: $data"></span><span data-bind="text: $parent.hello"></span>
</div>

如果计算出的可观察值改变了值,则只会重新估算计算值。

如果你把它放在根上,那么$root.hello将始终引用它。


但我认为可能创建一个自定义绑定,使用语法非常类似于你所显示的,但我不认为我会推荐它。沿着这些方向的东西(完全未经测试 - 呵呵,whaddyaknow,它有效,见下文):

ko.bindingHandlers.addThisVariable = {
    update: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        var value = ko.unwrap(valueAccessor());
        bindingContext.$data[ko.unwrap(value.name)] = ko.unwrap(value.value);
    }
};

示例(但同样,我真的认为我会使用计算机):

(function() {
  "use strict";

  ko.bindingHandlers.addThisVariable = {
    update: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
      var value = ko.unwrap(valueAccessor());
      bindingContext.$data[ko.unwrap(value.name)] = ko.unwrap(value.value);
    }
  };

  var vm = {
    foo: ko.observable("foo"),
    bar: ko.observable("bar"),
    list: ko.observableArray([
      'one', 'two', 'three'
    ])
  };

  ko.applyBindings(vm, document.body);
})();
<script src="//cdnjs.cloudflare.com/ajax/libs/knockout/3.1.0/knockout-min.js"></script>
<div data-bind="addThisVariable: { name: '$hello', value: foo() + bar() }, foreach: list">
  <span data-bind="text: $data"></span><span data-bind="text: $parent.$hello"></span>
</div>

这只会将其添加到当前VM(因此需要withforeach或其他任何内容的<{1}}或$parent 内的}绑定 ),但它仍然提供了一些你可以在HTML块中引用的本地东西。

答案 2 :(得分:1)

Knockouts foreach绑定具有as选项,可以执行您想要的操作。如果你有一个“某事”的数组,并且你希望能够将它们引用为$something.whatever,那么

<!-- ko foreach: {data: arrayOfSomethings, as: '$something'} -->
    <span data-bind="text: $something.foo"></span> <!-- works in any child context -->
<!-- /ko -->

另一方面,如果你只有一个“东西”......老实说,我可能会推荐Michael Best的let绑定......但如果你只想要一些有用的东西,不需要自定义绑定处理程序...

<!-- ko foreach: {data: [something], as: '$something'} --> <!-- ugly but it works -->
     <span data-bind="text: $something.foo"></span> <!-- works in any child context -->
<!-- /ko -->

(旁注,我实际上不建议使用“$ something”作为你的名字;我会留下$ knockout-defined东西的前缀,只是把你的东西称为“某事”;亲自)