淘汰高级声明javascript"用“-喜欢

Knockout advanced declaration javascript "with"-like

本文关键字:喜欢 quot 高级 声明 javascript 淘汰      更新时间:2023-09-26

我遇到了一些问题,需要在子元素(如$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"绑定,它不能回答我的答案

它想要一个临时的var,我需要它来填充子上下文,就像我们对所做的那样

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

不久前,我为自己创建了一个名为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>

这两个选项都不能为您提供JavaScript的with(但是,JavaScript的with有一些非常重要的维护问题),但这里有几个选项:


你最好的选择可能是在容器甚至根虚拟机上计算。

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绑定需要$parent$parent.$parent或其他),但它仍然为您提供了可以在HTML块中引用的本地内容。

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

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

另一方面,如果你只有一个"某物"。。。老实说,我可能会推荐迈克尔·贝斯特的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"作为您的名称;我会将$前缀留给敲除定义的东西,并直接称您的东西为"something)