如何使用KnockoutJS正确呈现jQuery Mobile Tab小部件项?

时间:2014-03-12 15:47:09

标签: jquery-mobile knockout.js

jsFiddle http://jsfiddle.net/nAgfQ/2/(有关说明和解决方法,请参阅HTML部分的顶部。)

方案

我使用jQuery Mobile(1.4.2)和KnockoutJS(3.1.0)构建了一个非常简单的基于标签的单页Web应用程序,用于向业务用户显示数据。

代码

这是JS:

    $(function () {

    var Tab = function (Title, TabID) {

        var self = this;

        self.Title = ko.observable(Title);
        self.TabID = ko.observable(TabID);

        self.TabHref = ko.computed(function () {
            return '#' + self.TabID();
        });

    };

    function DashboardViewModel() {

        var self = this;

        self.Title = ko.observable();
        self.DashboardID = ko.observable();

        self.tabs = ko.observableArray([
        new Tab("Tab 1", "tabs-1", []),
        new Tab("Tab 2", "tabs-2", [])]);


        self.refreshTabs = function () {
            $('#tabs').tabs("refresh").tabs("option", "active", 0);
            //Added to callback to convert navbar div into jQuery Mobile Navbar
            $('#dashboard_navbar').navbar();

        };


    }

    dvm = new DashboardViewModel();
    ko.applyBindings(dvm);

});

这是页面的正文内容:

<body>
<div data-role="page" id="page-1">
    <div data-role="header">
            <h1>jQuery Mobile Tabs Test</h1>

    </div>
    <div data-role="content">
        <div data-role="tabs" id="tabs">
           <div data-role="navbar" id="dashboard_navbar">

                <ul data-bind="template { foreach : tabs  }">
                    <li><a data-bind="attr : { href: TabHref } , text: Title" data-ajax="false"></a>

                    </li>
                </ul>
            </div>
            <div data-bind=" template { foreach :tabs, afterRender: refreshTabs}">
                <div data-bind="attr : { id: TabID }" class="ui-body-d ui-content">
                    <h4 data-bind="text: Title" />
                </div>
            </div>
        </div>
    </div>

</div></body>

问题

  • 当你在jQuery Mobile中有一个Tab小部件时,我们鼓励你声明一个元素,让 data-role 属性设置为&#34; navbar。&#34;
  • 当jQuery呈现页面时,它会查找所选元素的第一个 ul 子元素,并读取 ul <下面 li 元素的数量/ strong>即可。
  • 然后使用它来添加一个具有命名模式 ul-grid-N 的类,其中N是与找到的元素数减1相对应的字母表的字母(即 ul-grid-a 用于2个元素, ul-grid-b 用于3,等等。)如果只有一个元素,则使用特殊类 ul-grid-独奏

但是,当您使用KnockoutJS加载一组绑定选项卡时,您只需在 foreach 绑定下提供一个 li 元素作为模板。 jQuery Mobile只看到1个元素,因此添加 ul-grid-solo 类,然后导航栏 li 元素最终被渲染为堆叠在一起而不是水平对齐。

解决方法

我到目前为止的解决方案是删除&#34;导航栏&#34; data-role ,而是使用KnockoutJS的afterRender回调,在插入所有绑定选项卡后将元素转换为导航栏。 (请参阅 DashboardViewModel 对象中的* refreshTab * s函数。)

这很有效,但不太理想,因为它强制ViewModel知道一些关于View的内容,这是MVVM禁忌。

问题

  1. 我可以告诉jQuery Mobile在应用绑定之前不推迟将网格类应用到导航栏吗?我探索了它的API,但没有看到任何特别有用的东西。
  2. 我能用Knockout的自定义绑定做些什么吗?再次,尝试不将任何DOM操作注入ViewModel。
  3. 一般情况下,任何其他变通办法,对代码的评论等都会受到赞赏。

1 个答案:

答案 0 :(得分:1)

使用淘汰赛和jQuery Mobile一段时间后,我可以确认他们根本不能一起玩。我们的团队有一个可重复使用的淘汰赛自定义绑定列表,仅用于使用jQuery mobile,因为它们非常痛苦。

您基本上可以将以下变通方法或您自己的变通方法包装到您用来代替foreach的自定义绑定中。或者订阅对导航栏项目数组的更改并在那里更新。

基于jsFiddle的解决方法,尝试重新创建导航栏,您还必须删除jQuery mobile放入元素的动态标记。尝试添加此内容(source):

navbar.find("*").andSelf().each(function(){
    $(this).removeClass(function(i, cn){
         var matches = cn.match (/ui-[\w\-]+/g) || [];
             return (matches.join (' '));
         });
         if ($(this).attr("class") == "") {
             $(this).removeAttr("class");
         }
});

JSFiddle