骨干视图传递给jQuery Mobile

时间:2012-10-05 21:16:18

标签: jquery-mobile backbone-views

我一直在尝试将backbonejs和jqm一起使用。

我可以渲染主页。该页面有一个用户可以点击的列表。所选项目应显示详细信息页面,其中包含所选列表项的信息。详细信息页面是一个骨干视图,其中包含在项目视图对象中呈现的模板。

详细信息视图.render()生成html ok,我将主页面div标签的html设置为渲染项目的详细标记。它看起来像这样:

podClicked: function (event) {             
        console.log("PodListItemView: got click from:" + event.target.innerHTML + " id:" + (this.model.get("id") ? this.model.get("id") : "no id assigned") + "\n\t CID:" + this.model.cid);
        var detailView = new PodDetailView({ model: this.model });
        detailView.render();
    },

详细视图的渲染如下所示:

    render: function () {
        this.$el.html(this.template({ podId: this.model.get("podId"), isAbout_Name: this.model.get("isAbout_Name"), happenedOn: this.model.get("happenedOn") }));
        var appPageHtml = $(app.el).html($(this.el));
        $.mobile.changePage("");  // <-- vague stab in the dark to try to get JQM to do something.  I've also tried $.mobile.changePage(appPageHtml).
        console.log("PodDetailView: render");
        return this;
    }

我可以看到详细信息的视图已经通过检查Chrome的开发工具html编辑器在页面上呈现,但它没有显示在页面上。我看到的只是一个空白页。

我尝试了$ .mobile.changePage()但是,如果没有URL,则会抛出错误。

如何让JQM将它的类标签应用于渲染的html?

HTML和模板如下所示:

<!-- Main Page -->
<div id="lessa-app" class="meditator-image" data-role="page"></div>
<!-- The rest are templates processed through underscore -->
<script id="app-main-template" type="text/template">
    <div data-role="header">
        <h1>@ViewBag.Title</h1>
    </div>
    <!-- /header -->

    <div id="main-content" data-role="content">
        <div id="pod-list" data-theme="a">
            <ul data-role="listview" >
            </ul>
        </div>
    </div>

    <div id="main-footer" data-role='footer'>
        <div id="newPod" class="ez-icon-plus"></div>
    </div>
</script>
<script id="poditem-template" type="text/template">
   <span class="pod-listitem"><%= isAbout_Name %></span> <span class='pod-listitem ui-li-aside'><%= happenedOn %></span> <span class='pod-listitem ui-li-count'>5</span>
</script>
<script id="page-pod-detail-template" type="text/template">
    <div data-role="header">
        <h1>Pod Details</h1>
    </div>
    <div data-role="content">
        <div id='podDetailForm'>
            <fieldset data-role="fieldcontain">
                <legend>PodDto</legend>
                <label for="happenedOn">This was on:</label>
                <input type="date" name="name" id="happenedOn" value="<%= happenedOn %>" />
            </fieldset>
        </div> 
        <button id="backToList" data-inline="false">Back to list</button>
    </div>
    <div data-role='footer'></div>
</script>

提前感谢任何建议......这是否可行?

1 个答案:

答案 0 :(得分:0)

我终于找到了办法。我的原始代码对此过程的成功有几个障碍。

首先要拦截jquerymobile的(v.1.2.0)changePage事件,如下所示: (我已经调整了jqm文档的大纲,并留在了有用的评论中:见http://jquerymobile.com/demos/1.2.0/docs/pages/page-dynamic.html

    $(document).bind("pagebeforechange", function (e, data) {

        // We only want to handle changePage() calls where the caller is
        // asking us to load a page by URL.
        if (typeof data.toPage === "string") {

            // We are being asked to load a page by URL, but we only
            // want to handle URLs that request the data for a specific
            // category.
            var u = $.mobile.path.parseUrl(data.toPage),
                re = /^#/;

            // don't intercept urls to the main page allow them to be managed by JQM
            if (u.hash != "#lessa-app" && u.hash.search(re) !== -1) {

                // We're being asked to display the items for a specific category.
                // Call our internal method that builds the content for the category
                // on the fly based on our in-memory category data structure.
                showItemDetail(u, data.options); // <--- handle backbone view.render calls in this function

                // Make sure to tell changePage() we've handled this call so it doesn't
                // have to do anything.
                e.preventDefault();
            }
        }
    });

在项目的列表骨干视图事件声明中进行changePage()调用,该声明传递给podClicked方法,如下所示:

     var PodListItemView = Backbone.View.extend({
        tagName: 'li', // name of (orphan) root tag in this.el
        attributes: { 'class': 'pod-listitem' },

        // Caches the templates for the view
        listTemplate: _.template($('#poditem-template').html()),
        events: {
            "click .pod-listitem": "podClicked"
        },
        initialize: function () {
            this.model.bind('change', this.render, this);
            this.model.bind('destroy', this.remove, this);
        },
        render: function () {
            this.$el.html(this.listTemplate({ podId: this.model.get("podId"), isAbout_Name: this.model.get("isAbout_Name"), happenedOn: this.model.get("happenedOn") }));
            return this;
        },
        podClicked: function (event) {
            $.mobile.changePage("#pod-detail-page?CID='" + this.model.cid + "'");
        },
        clear: function () {
            this.model.clear();
        }
    });

在'showItemDetail'函数中,url的查询部分被解析为项目主干模型的CID。我再次调整了上面显示的jquerymobile.com链接中提供的代码。

问题:我还在弄清楚,将showItemDetail()中的代码放在视图的render()方法中是否更好。具有已定义的功能似乎有损于骨干网的架构模型。另一方面,让render()函数知道调用JQM changePage似乎违反了“关注点分离”的原则。任何人都可以提供一些见解和指导吗?

    // the passed url looks like #pod-detail-page?CID='c2'
    function showItemDetail(urlObj, options) {

        // Get the object that represents the item selected from the url
        var pageSelector = urlObj.hash.replace(/\?.*$/, "");
        var podCid = urlObj.hash.replace(/^.*\?CID=/, "").replace(/'/g, "");

        var $page = $(pageSelector),
           // Get the header for the page.
           $header = $page.children(":jqmData(role=header)"),
           // Get the content area element for the page.
           $content = $page.children(":jqmData(role=content)");

        // The markup we are going to inject into the content area of the page.
        // retrieve the selected pod from the podList by Cid
        var selectedPod = podList.getByCid(podCid);

        // Find the h1 element in our header and inject the name of the item into it
        var headerText = selectedPod.get("isAbout_Name");
        $header.html("h1").html(headerText);

        // Inject the item info into the content element
        var view = new PodDetailView({ model: selectedPod });
        var viewElHtml = view.render().$el.html();
        $content.html(viewElHtml);

        $page.page();

        // Enhance the listview we just injected.
        var fieldContain = $content.find(":jqmData(role=listview)");
        fieldContain.listview();

        // We don't want the data-url of the page we just modified
        // to be the url that shows up in the browser's location field,
        // so set the dataUrl option to the URL for the category
        // we just loaded.
        options.dataUrl = urlObj.href;

        // Now call changePage() and tell it to switch to
        // the page we just modified.
        $.mobile.changePage($page, options);
    }

所以上面提供了事件管道。

我遇到的另一个问题是页面设置不正确。最好将页面框架放在主html中,而不是将其放在下划线模板中以便稍后呈现。我认为避免jqm接管时html不存在的问题。

<!-- Main Page -->
<div id="lessa-app" data-role="page">
  <div data-role="header">
    <h1></h1>
  </div>
  <!-- /header -->
  <div id="main-content" data-role="content">
    <div id="pod-list" data-theme="a">
      <ul data-role="listview">
      </ul>
    </div>
  </div>
  <div id="main-footer" data-role='footer'>
    <div id="main-newPod" class="ez-icon-plus"></div>
  </div>
</div>
<!-- detail page -->
<div id="pod-detail-page" data-role="page">
    <div data-role="header">
        <h1></h1>
    </div>
    <div id="detail-content" data-role="content">
        <div id="pod-detail" data-theme="a">
        </div>
    </div>
  <div id="detail-footer" data-role='footer'>
     <a href="#lessa-app" data-role="button" data-mini="true">back</a>
  </div>
</div>