【问题标题】:combine dynamic and static classes through css binding, knockout.js通过css绑定、knockout.js结合动态类和静态类
【发布时间】:2013-10-15 20:54:42
【问题描述】:

在 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,但出现错误。有没有办法做到这一点?

【问题讨论】:

    标签: javascript knockout.js


    【解决方案1】:

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

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

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

    【讨论】:

    • 确保将任何预定义的类添加到此绑定中(使用实际类属性添加的类)。
    • 我认为 josh_bailey4 的评论应该整合到答案中,因为这是一件非常需要注意的事情,尤其是在编辑现有标记时,该标记已经具有 class 属性目标元素。无论如何,赞成。
    • 这个答案似乎不适用于动态类名。如果此处的“颜色”可观察值发生变化,它将删除通过“css”绑定添加的所有类。参见示例:jsfiddle.net/rocketmonkeys/tzj1zj31
    • 意识到这个解决方案不能处理可观察到的变化为时已晚。无法撤消我的赞成票。 Roy's answer 为我工作,
    【解决方案2】:

    不久前我通过将css 绑定克隆为css2 解决了这个问题。

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

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

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

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

    【讨论】:

    • 我倾向于支持@Aleksey 对此的回答,但这种方法是一种有趣的处理方式。
    • 这是一个有效的解决方案,唯一一个运作良好的解决方案。
    【解决方案3】:

    您最好的选择可能是不要将它们结合起来。而是使用视图模型的计算属性将它们组合成一个可以动态绑定的属性。这样,您还可以避免使用 number()

    像这样,例如:

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

    查看这个工作示例:http://jsfiddle.net/tT9PK/4/

    【讨论】:

    • 很幸运,这个答案对 OP 有用。大多数时候这样做只会导致大量计算(思考列表)和耦合代码(更难测试)。 Aleksey 的答案在下面,josh_bailey4 的评论是一个更优雅的解决方案,恕我直言,这应该是公认的答案,而不是这个。只是我的 2 美分。
    • @Mtz:我不同意,并且不涉及“运气”。我认为不使用number() &lt; 10 之类的逻辑来污染视图要干净得多。这就是拥有视图模型的意义所在。
    • colorAndTrans 可以带一个参数吗,例如如果有循环那么我们可以发送一个参数作为循环中项目的值吗?
    • 是的,小问题 - 使用 pureComputed 而不是 computed 进行一些有用的性能优化。
    【解决方案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 }"
    

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

    【讨论】:

      【解决方案5】:

      如果您真的遇到复杂的样式情况,只需将所有内容累积在计算属性中。你可以像 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 对其进行评估。

      【讨论】:

        【解决方案6】:

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

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

        也许在提出问题的时候不支持 (Idk),但当前 knockout 也可以结合这些类:data-bind="css: computed"

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

        【讨论】:

        • 我个人喜欢这种计算 observables 的实现。这无疑是在不扩展淘汰框架的情况下完成提问者请求的功能的最佳方式。但是,当由 CSS 绑定切换的类以对象格式显示时,我发现维护使用敲除构建的代码库要容易得多。我与一大群人一起工作,我们尽量避免使用隐藏视图模型内的类名的 CSS 绑定。这种开发策略可以很容易地从标记中看到正在发生的事情。这就是我选择扩展 KO 的原因。
        【解决方案7】:

        更多选择:

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

        <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

        【讨论】:

          【解决方案8】:

          通过计算属性名称(对于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

          【讨论】:

            【解决方案9】:

            我会在您的视图模型中创建 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>

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2015-09-15
              • 2021-08-26
              • 1970-01-01
              • 2012-06-16
              • 2012-10-29
              • 1970-01-01
              相关资源
              最近更新 更多