javascript 通过 css 绑定,knockout.js 结合动态和静态类

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19256093/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 14:53:59  来源:igfitidea点击:

combine dynamic and static classes through css binding, knockout.js

javascriptknockout.js

提问by Artem Svirskyi

In knockout.js we can use css binding for static classes

在knockout.js 中,我们可以对静态类使用css 绑定

<div data-bind="css: {'translucent ': number() < 10}">static dynamic css classes</div>

and dynamic

和动态

<div data-bind="css: color">static dynamic css classes</div>

I've tried http://jsfiddle.net/tT9PK/1/to combine it in something like

我试过http://jsfiddle.net/tT9PK/1/将它组合成类似的东西

css: {color, translucent: number() < 10}

to get dynamic class colorand static translucentat the same time, but I get an error. Is there a way to do that?

同时获取动态类color和静态类translucent,但出现错误。有没有办法做到这一点?

回答by Aleksey

You can add dynamic class by cssproperty and then add static class by attrproperty

您可以通过添加动态类css属性,然后通过添加静态类attr属性

<div data-bind="attr: { 'class': color }, css: { 'translucent': number() < 10 }">
  static dynamic css classes
</div>

Be sure to add any predefined classes to this binding attr: { 'class': color }

确保将任何预定义的类添加到此绑定 attr: { 'class': color }

回答by Simon_Weaver

I solved this problem a while back by just cloning the cssbinding as css2.

不久前,我通过将css绑定克隆为css2.

 ko.bindingHandlers['css2'] = ko.bindingHandlers.css;

Normally you can't use the same binding handler twice in a data-bind attribute, so this allowed me to do the following:

通常,您不能在数据绑定属性中两次使用相同的绑定处理程序,因此这允许我执行以下操作:

<div data-bind="css: color, css2: { 'translucent': number() < 10 }">static dynamic css classes</div>

I can't quite decide whether I still prefer this, or @Aleksey's answer, but this may be the only choice if you have multiple dynamic classes to add.

我不能完全确定我是否仍然更喜欢这个,或者@Aleksey 的答案,但是如果您要添加多个动态类,这可能是唯一的选择。

回答by beauXjames

Correct...and to launch you even further, check out this modification.

正确......为了进一步启动您,请查看此修改。

http://jsfiddle.net/Fv27b/2/

http://jsfiddle.net/Fv27b/2/

Here, you'll see that not only are we combining the options, but we're creating our own binding entirely...which results in a much more portable extension of not just this view model, but any view model you may have in your project...so you'll only need to write this one once!

在这里,你会看到我们不仅组合了选项,而且我们完全创建了我们自己的绑定......这不仅会导致这个视图模型的更便携的扩展,而且你可能拥有的任何视图模型你的项目……所以你只需要写一次这个!

ko.bindingHandlers.colorAndTrans = {
    update: function(element, valAccessor) {
        var valdata = valAccessor();
        var cssString = valdata.color();
        if (valdata.transValue() < 10) cssString += " translucent";
        element.className = cssString;
    }
}

To invoke this, you just use it as a new data-bind property and can include as many (or as few) options as possible. Under this specific condition, I might have just provided $data, however if you're wanting a reusable option you need to be more specific as to what data types you need as parameters and not all view models may have the same properties.

要调用它,您只需将它用作新的数据绑定属性,并且可以包含尽可能多(或尽可能少)的选项。在这种特定条件下,我可能刚刚提供了 $data,但是如果您想要一个可重用的选项,您需要更具体地说明您需要作为参数的数据类型,并且并非所有视图模型都可能具有相同的属性。

data-bind="colorAndTrans: { color: color, transValue: number }"

Hope this does more than answer your question!

希望这不仅仅是回答您的问题!

回答by Matt Burland

Your best bet is probably not to combine them. Instead use a computed property of your view model to combine them into a single property that you can bind dynamically. That way you can also avoid putting logic in your view with the number() < 10 binding, which is cleaner anyway.

您最好的选择可能是不要将它们结合起来。而是使用视图模型的计算属性将它们组合成一个可以动态绑定的属性。这样,您还可以避免使用 number() < 10 绑定在视图中放置逻辑,这无论如何都更清晰。

Like this, for example:

像这样,例如:

viewModel.colorAndTrans = ko.computed(function () {
    var cssString = viewModel.color();
    if (viewModel.number() < 10) {
        cssString += " translucent"
    }
    return cssString;
});

See this working example: http://jsfiddle.net/tT9PK/4/

请参阅此工作示例:http: //jsfiddle.net/tT9PK/4/

回答by mikus

If you really get into complicated styling case, just accumulate all in the computed property. You can do it as Alex mentioned or a bit more readable:

如果您真的遇到复杂的样式案例,只需在计算属性中累积所有内容即可。你可以像亚历克斯提到的那样做,或者更具可读性:

vm.divStyle = ko.computed(function() {
        var styles = [];

        if (vm.isNested()) styles.push('nested');
        if (vm.isTabular()) styles.push('tabular');
        else styles.push('non-tabular');
        if (vm.color()) styles.push(vm.color());

        return styles.join(' ');
});

the main drawback is that you're moving a part of view definition into the viewmodel, that should be more independent. The alternative is to provide all the logic above as a plain js function call, and let knockout evaluate it.

主要缺点是您将视图定义的一部分移动到视图模型中,这应该更加独立。另一种方法是将上述所有逻辑作为一个普通的 js 函数调用提供,并让 Knockout 对其进行评估。

回答by Roy J

A couple more options:

还有几个选择:

Similar to the suggestions to use a computed, you can inline the expression:

类似于使用计算的建议,您可以内联表达式:

<div data-bind="css: [color(), (number() < 10 ? 'translucent' : 'notTranslucent')].join(' ')">static dynamic css classes</div>

As an alternative to a custom binding handler that is specific to this case, you can make one that takes an array of mixed css specs and passes them to the original css handler:

作为特定于这种情况的自定义绑定处理程序的替代方案,您可以制作一个接受一组混合 css 规范并将它们传递给原始 css 处理程序的方法:

<div data-bind="cssArray: [color, {translucent: number() < 10}]">static dynamic css classes</div>

The handler:

处理程序:

 ko.bindingHandlers.cssArray = {
    update: function (element, valueAccessor, allBindingsAccessor, data, context) {
        var arr = ko.unwrap(valueAccessor());
      for (var i=0; i<arr.length; ++i) {
        var wrapped = function () { return ko.unwrap(arr[i]) };
        ko.bindingHandlers.css.update(element, wrapped, allBindingsAccessor, data, context);
      }
    }
  }

Fiddle demo

小提琴演示

回答by Kenneth Moore

There is a more elegant solution to this problem via computed property names (for FF>34, Chrome, Safari>7.1):

通过计算属性名称(对于FF>34、Chrome、Safari>7.1有一个更优雅的解决方案:

<div data-bind="css: { [color]: true,'translucent': number() < 10 }">
    static dynamic css classes
</div>

Whereas coloris a property with a string value.

color是具有字符串值的属性。

If the value of coloris an observable then we need to clear the classname before that observable updates. If we do not do this then each change will add another class and not remove the previous one. This can easily be accomplished manually but I wrote an extender for those who are interested.

如果 的值color是一个 observable,那么我们需要在该 observable 更新之前清除类名。如果我们不这样做,那么每次更改都会添加另一个类,而不是删除前一个。这可以很容易地手动完成,但我为那些有兴趣的人写了一个扩展程序。

ko.extenders.css = function(target, value) {
  var beforeChange;
  var onChange;

  //add sub-observables to our observable
  target.show = ko.observable(true);

  beforeChange = function(oldValue){
    target.show(false);
  }
  onChange = function(newValue){
    target.show(true);
  }
  target.subscribe(beforeChange, null, "beforeChange");
  target.subscribe(onChange);
  return target;
};

With this extender, your JavaScript code would look like this:

使用此扩展程序,您的 JavaScript 代码将如下所示:

function MyViewModel() {
    this.color = ko.observable("red").extend({ css: true });
    this.number = ko.observable(9)
};

And your markup would be this simple:

你的标记会很简单:

<div data-bind="css: { [color()]: color.show(),'translucent': number() < 10 }">
    static dynamic css classes
</div>

I have a code pen demonstrating this technique: http://codepen.io/USIUX/pen/WryGZQ

我有一个代码笔演示这种技术:http: //codepen.io/USIUX/pen/WryGZQ

I have also submitted an issue with knockout in hopes that one day the custom extender will not be necessary: https://github.com/knockout/knockout/issues/1990

我还提交了一个关于淘汰赛的问题,希望有一天不需要自定义扩展程序:https: //github.com/knockout/knockout/issues/1990

回答by Alex

Nice question, the problem seems to be the binding cssisn't thought to mix the two kinds, color(): color() != ''doesn't work (would be nice).

好问题,问题似乎是绑定css不被认为是混合这两种,color(): color() != ''不起作用(会很好)。

I like @Simon_waver's answer approach, simple and practical.

我喜欢@Simon_waver 的回答方式,简单实用。

Maybe at the time of the question wasn't supported (Idk) but with current knockoutalso combining the classes works: data-bind="css: computed"

也许在提出问题的时候不支持(Idk),但目前的淘汰赛也结合了这些课程:data-bind="css: computed"

viewModel.computed = ko.pureComputed(function() {
   return viewModel.color() + (viewModel.number() < 10 ? ' translucent' : '');
});

回答by user3297291

I'd create the cssbinding value in your viewmodel. You can define a computedthat returns either an object or string.

我会css在您的视图模型中创建绑定值。您可以定义computed返回对象或字符串的 。

Some examples, using ES2015:

一些示例,使用 ES2015:

const App = function() {
  this.number = ko.observable(12);
  this.color = ko.observable("red");
  
  this.cssConfigObj = ko.pureComputed(() => ({
    "italic": this.number() > 10,
    [this.color()]: true
  }));
  
  this.cssConfigStr = ko.pureComputed(() => 
    `${this.color()} ${this.number() > 10 ? "italic" : ""}`
  );
};

ko.applyBindings(new App());
.monospaced {
  font-family: monospace;
}

.italic {
  font-style: italic;
}

.red {
  color: red; 
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<div
  class="monospaced"
  data-bind="css: cssConfigObj"
>Hello world</div>

<div
  class="monospaced"
  data-bind="css: cssConfigStr"
>Hello world</div>