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

时间:2022-12-03 10:33:18

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 color and static translucent at the same time, but I get an error. Is there a way to do that?

同时获得动态类颜色和静态半透明,但是我收到错误。有没有办法做到这一点?

8 个解决方案

#1


53  

You can add dynamic class by css property and then add static class by attr property

您可以通过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}

#2


13  

I solved this problem a while back by just cloning the css binding 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:

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

<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.

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

#3


4  

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!

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

#4


3  

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/

#5


2  

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:

如果你真的进入复杂的样式案例,只需在计算属性中累积所有内容。您可以像Alex提到的那样或更具可读性:

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.

主要的缺点是你将视图定义的一部分移动到viewmodel中,它应该更加独立。另一种方法是将上面的所有逻辑提供为普通的js函数调用,并让knockout评估它。

#6


1  

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

小提琴演示

#7


1  

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 color is a property with a string value.

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

If the value of color is 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的值是可观察的,那么我们需要在可观察的更新之前清除classname。如果我们不这样做,那么每个更改将添加另一个类而不删除前一个类。这可以很容易地手动完成,但我为那些感兴趣的人写了一个扩展器。

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

#8


0  

Nice question, the problem seems to be the binding css isn'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 knockout also 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' : '');
});

#1


53  

You can add dynamic class by css property and then add static class by attr property

您可以通过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}

#2


13  

I solved this problem a while back by just cloning the css binding 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:

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

<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.

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

#3


4  

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!

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

#4


3  

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/

#5


2  

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:

如果你真的进入复杂的样式案例,只需在计算属性中累积所有内容。您可以像Alex提到的那样或更具可读性:

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.

主要的缺点是你将视图定义的一部分移动到viewmodel中,它应该更加独立。另一种方法是将上面的所有逻辑提供为普通的js函数调用,并让knockout评估它。

#6


1  

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

小提琴演示

#7


1  

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 color is a property with a string value.

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

If the value of color is 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的值是可观察的,那么我们需要在可观察的更新之前清除classname。如果我们不这样做,那么每个更改将添加另一个类而不删除前一个类。这可以很容易地手动完成,但我为那些感兴趣的人写了一个扩展器。

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

#8


0  

Nice question, the problem seems to be the binding css isn'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 knockout also 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' : '');
});