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

时间:2013-10-08 19:02:26

标签: javascript knockout.js

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

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

和动态

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

我已经尝试http://jsfiddle.net/tT9PK/1/将其组合在像

这样的内容中
css: {color, translucent: number() < 10}

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

9 个答案:

答案 0 :(得分:57)

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

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

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

答案 1 :(得分:14)

我暂时将css绑定克隆为css2,解决了这个问题。

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

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

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

我无法确定我是否仍然喜欢这个,或@Allksey的答案,但如果您要添加多个动态类,这可能是唯一的选择。

答案 2 :(得分:4)

正确......并进一步发动你,看看这个修改。

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

在这里,您将看到我们不仅将选项组合在一起,而且我们正在完全创建自己的绑定...这导致了更多的可移植扩展,不仅仅是这个视图模型,而且任何视图模型都可以可能在你的项目中...所以你只需要写一次这个!

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

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

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

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

答案 3 :(得分:3)

你最好的选择可能不是将它们结合起来。而是使用视图模型的计算属性将它们组合成可以动态绑定的单个属性。这样你也可以避免在你的视图中使用数字()&lt; 10绑定,无论如何都是清洁的。

像这样,例如:

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

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

答案 4 :(得分:2)

如果你真的进入复杂的样式案例,只需在计算属性中累积所有内容。您可以像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(' ');
});

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

答案 5 :(得分:1)

很好的问题,问题似乎是绑定css并未考虑混合这两种,color(): color() != ''不起作用(会很好)。

我喜欢@ Simon_waver的答案方法,简单实用。

也许在问题尚未得到支持时(Idk),但目前的淘汰也将这些类合并起来:data-bind="css: computed"

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

答案 6 :(得分:1)

还有更多选择:

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

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

作为特定于此情况的自定义绑定处理程序的替代方法,您可以创建一个采用混合css规范数组并将其传递给原始css处理程序的处理程序:

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

处理程序:

 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)

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

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

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

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

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;
};

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

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

你的标记就是这么简单:

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

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

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

答案 8 :(得分:0)

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

使用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>