Knockout与Require框架同时使用时的visible绑定的问题,造成的影响,以及解决的方法。

Knockout 可以将 visible 绑定到DOM 元素上,使得该元素的hidden 或visible 状态取决于绑定的值。

查看以下knockout的描述,http://knockoutjs.com/documentation/visible-binding.html

When the parameter resolves to a false-like value (e.g., the boolean value false, or the numeric value 0, or null, or undefined),  
the binding sets yourElement.style.display to none, causing it to be hidden. This takes priority over any display style you’ve defined using CSS。 当这个参数是一个假值时(举例来说,布尔值的false , 数值0,或者null,或者undefined),绑定时候设置你的元素的style.display是none,从而使之隐藏起来。这个优先级要高于CSS中定义的. When the parameter resolves to a true-like value (e.g., the boolean value true, or a non-null object or array), the binding removes the yourElement.style.display value,
causing it to become visible。 当这个参数是一个真值时(举例来说,布尔值是true,或者非空对象与数组),绑定时候移除你display的值,从来显示出来

当单独使用knockout框架时,这个visible绑定运行起来相当好,但是,当Knockout和Require两个框架同时使用时,就出问题了。

先看一个例子,这个例子里有有两个div,第一次加载页面时显示div1,隐藏div2,当按下一步按钮时,隐藏div1,显示div2,最后点返回按钮时,显示div1,隐藏div2。

ko_visible.htm代码,

<html>
<head>
   <script src="../lib/require/require.js" data-main="ko_visible"></script>
</head>
<body  >
  <div id="div1" data-bind="visible: showVisibleDiv1">
  <p>First name: <span ></span></p>
  <p>Last name: <span ></span></p>
  <p>Full name: <span ></span></p>
  <input type="text" id="inputAddress"  /> *
  <input type="text" id="inputMoney"  /> *
  <input type="button" id="btnSave" value="下一步" data-bind="click: SaveClick" />
  </div>

  <div id="div2" data-bind="visible: showVisibleDiv2">
      <table>
          <tr>
              <td>标题</td><td>内容</td>
          </tr>
          <tr>
              <td></td><td></td>
          </tr>
      </table>
      <input type="button" id="btnNext" value="返回" data-bind="click: NextClick" />
  </div>

</body>
</html>

  

ko_visible.js

require.config({
    paths: {
        "knockout": "../lib/knockout/knockout-2.3.0",
        "jquery": "../lib/jquery/jquery-1.9.1.min"
    }

});

require(['jquery', 'knockout'], function ($, ko) {

    //数据绑定
    $(document).ready(function () {
        var viewModel = {
            showVisibleDiv1: ko.observable(true),
            showVisibleDiv2: ko.observable(false),
            SaveClick: function () {
                viewModel.showVisibleDiv1(false);
                viewModel.showVisibleDiv2(true);
            },
            NextClick: function () {
              viewModel.showVisibleDiv1(true);
              viewModel.showVisibleDiv2(false);                
            }
        };
        ko.applyBindings(viewModel);  
    });
});

当运行此页面时,效果如下图,div1,div2同时显示,然后, div2因为visible=false的缘故,又迅速消失。

当页面中存在多个步骤的div,想一步步执行并控制某些div显示时, 这个效果是让人不能接受的.

当页面初始加载时,因为Require的延迟加载特性(也就是不先加载js,而是先加载元素,异步加载js),当knockout代码还没有执行时,元素是没有被隐藏的,这一点是致命的。

所以,修改的方法有两个:

1.不使用Require框架。

例子如下: 

ko_visible1.htm

<html>
<head>
  <script type="text/javascript" src="../lib/knockout/knockout-2.3.0.js"></script>
  <script type="text/javascript" src="../lib/jquery/jquery-1.9.1.min.js"></script>
  <script type="text/javascript" src="ko_visible1.js"></script>
</head>
<body  >
  <div id="div1" data-bind="visible: showVisibleDiv1">
  <p>First name: <span ></span></p>
  <p>Last name: <span ></span></p>
  <p>Full name: <span ></span></p>
  <input type="text" id="inputAddress"  /> *
  <input type="text" id="inputMoney"  /> *
  <input type="button" id="btnSave" value="下一步" data-bind="click: SaveClick" />
  </div>

  <div id="div2" data-bind="visible: showVisibleDiv2">
      <table>
          <tr>
              <td>标题</td><td>内容</td>
          </tr>
          <tr>
              <td></td><td></td>
          </tr>
      </table>
      <input type="button" id="btnNext" value="返回" data-bind="click: NextClick" />
  </div>

</body>
</html>

ko_visible1.js

    //数据绑定
    $(document).ready(function () {

        var viewModel = {
            showVisibleDiv1: ko.observable(true),
            showVisibleDiv2: ko.observable(false),
            SaveClick: function () {
                viewModel.showVisibleDiv1(false);
                viewModel.showVisibleDiv2(true);
            },
            NextClick: function () {
              viewModel.showVisibleDiv1(true);
              viewModel.showVisibleDiv2(false);                
            }
        };
        ko.applyBindings(viewModel);  
    });

  

2.如果必须使用Require框架,那在这种场合,建议不要使用visible,还是使用css的样式控制。

例子如下:

ko_display.htm

<html>
<head>
   <script src="../lib/require/require.js" data-main="ko_display"></script>
</head>
<body  >
  <div id="div1" data-bind="visible: showVisibleDiv1">
  <p>First name: <span ></span></p>
  <p>Last name: <span ></span></p>
  <p>Full name: <span ></span></p>
  <input type="text" id="inputAddress"  /> *
  <input type="text" id="inputMoney"  /> *
  <input type="button" id="btnSave" value="下一步" data-bind="click: SaveClick" />
  </div>

  <div id="div2" style="display:none">
      <table>
          <tr>
              <td>标题</td><td>内容</td>
          </tr>
          <tr>
              <td></td><td></td>
          </tr>
      </table>
      <input type="button" id="btnNext" value="返回" data-bind="click: NextClick" />
  </div>

</body>
</html>

ko_display.js

require.config({
    paths: {
        "knockout": "../lib/knockout/knockout-2.3.0",
        "jquery": "../lib/jquery/jquery-1.9.1.min"
    }

});

require(['jquery', 'knockout'], function ($, ko) {

    //数据绑定
    $(document).ready(function () {

        var viewModel = {
            showVisibleDiv1: ko.observable(true),

            SaveClick: function () {
                viewModel.showVisibleDiv1(false);
                $("#div2").show();
            },
            NextClick: function () {
                viewModel.showVisibleDiv1(true);
                $("#div2").hide();                           
            }
        };
        ko.applyBindings(viewModel);  
    });
});

以上是本人在项目中遇到的问题总结,如有谬误之处,还请大家指正!

 

posted on 2014-01-08 11:03  BobLiu  阅读(2058)  评论(3编辑  收藏  举报