如何使用 Backbone.js 在 changePage 后显示 JQuery Mobile 主页面

Posted

技术标签:

【中文标题】如何使用 Backbone.js 在 changePage 后显示 JQuery Mobile 主页面【英文标题】:How to get main JQuery Mobile page to display after changePage using Backbone.js 【发布时间】:2013-12-06 07:54:23 【问题描述】:

我正在开发一个同时使用 RequireJS 和 BackboneJS 的 JQuery Mobile 应用程序 (1.4rc1)。该应用程序还没有那么复杂,但是太多了。我已经能够设置路由器并且它正在正确调用路由方法。我的页面,除了主页(位于index.html),保存在一个名为“/pages”的目录中。

应用程序加载正常并调用家庭路由器功能。稍后我将禁用该行为。 我点击登录链接,它会加载 /pages/login-page.html 并将页面添加到 DOM 并显示它。

问题: 当我点击后退按钮时,将调用 home 的路由器功能,然后调用 $.mobile.changePage("#mainpage") 但不会重新显示主页,也不会显示任何错误。

我已经确定 mainpage 仍在 DOM 中,并且正在调用正确的路由器函数。

为什么即使我调用了changePage,主页也不会重新显示? 日志:

before start mobileRouter.js:5
before home: http://localhost:8080/host/index.html mobileRouter.js:14
after home: http://localhost:8080/host/index.html#mainpage mobileRouter.js:16
after start mobileRouter.js:7
before login: http://localhost:8080/host/index.html#mainpage mobileRouter.js:19
after login: http://localhost:8080/host/index.html mobileRouter.js:21
before home: http://localhost:8080/host/pages/login-page.html mobileRouter.js:14
after home: http://localhost:8080/host/index.html#mainpage mobileRouter.js:16

相关代码:

mobileRouter.js

define(["jquery", "backbone"],
        function($, Backbone) 
            var Router = Backbone.Router.extend(
                initialize: function() 
                    console.log("before start");
                    Backbone.history.start();
                    console.log("after start");
                ,
                routes: 
                    "": "mainPage",
                    "loginpage": "loginPage",
                ,
                mainPage: function() 
                    console.log("before home: " + document.baseURI);
                    $.mobile.changePage("#mainpage");
                    console.log("after home: " + document.baseURI);
                ,
                loginPage: function() 
                    console.log("before login: " + document.baseURI);
                    $.mobile.changePage("pages/login-page.html");
                    console.log("after login: " + document.baseURI);
                
            );
            return Router;
        );

index.html

<!doctype html>
<html class="no-js ui-mobile-rendering" lang="en">
    <head>
    <title>The Measure Of It</title>
    <meta name="description" content="">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="lib/dev/jquery.mobile.structure-1.4.0-rc.1.css">
    <link rel="stylesheet" href="lib/dev/jquery.mobile.theme-1.4.0-rc.1.css">
    <script src="require.js" data-main="mobile"></script>
    </head>
    <body>
    <div data-role="page" id="mainpage">
        <div data-role="header">
        <h1>Main Page</h1>
        </div><!-- /header -->

        <div data-role="content">

        <p><a href="#loginpage">Login</a></p>
        </div><!-- /content -->

        <div data-role="footer">
        <h4>Page Footer</h4>
        </div><!-- /footer -->
    </div>
    </body>
</html>

/pages/login-page.html

<!doctype html>
<html lang="en">
    <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>page demo</title>
    </head>
    <body>
    <div data-role="page" id="loginpage">
        <div data-role="header">
        <h1>Login</h1>
        </div>
        <div data-role="content">
        <h2>email</h2>
        <h2>password</h2>
        </div>
        <div data-role="footer">
        <h1>Login Footer</h1>
        </div>
    </div>
    </body>
</html>

mobile.js

require.config(
    paths: 
        "jquery": "lib/dev/jquery-1.10.2",
        "jquerymobile": "lib/dev/jquery.mobile-1.4.0-rc.1",
        "underscore": "lib/dev/lodash",
        "backbone": "lib/dev/backbone",
        "routers": "app/routers",
    ,
    shim: 
        "backbone": 
            "deps": ["underscore", "jquery"],
            "exports": "Backbone" 
        
    
);

require(["jquery", "backbone", "routers/mobileRouter"], function($, Backbone, Mobile) 
    $(document).on("mobileinit",
            function() 
                $.mobile.linkBindingEnabled = false;
                $.mobile.hashListeningEnabled = false;
            
    );

    require(["jquerymobile"], function() 
        this.router = new Mobile();
    );
);

【问题讨论】:

$.mobile.changePage() 在 jqm 1.4 中已弃用并替换为$.mobile.pageContainer.pagecontainer ("change", "#page_id");,试试看。 相同的行为,但很高兴知道。 在更改页面中尝试 index.html 而不是 #mainpage 我希望不要陷入这个特殊问题,但是......它失败了,但它确实在 index.html 上执行了 GET。这有两个问题:它不需要执行 GET,因为主页面在 DOM 中,并且由于我不想处理的错误(但)它尝试从同一个页面加载 index.html目录,因为它从中加载登录页面,因此找不到它。 我不是骨干专家,但请帮我一个忙,当你点击返回按钮console.log($.mobile.pageContainer.pagecontainer("getActivePage").prev("[data-role=page]").length);时添加这一行如果它返回0,那么登录页面就没有前一页了。也试试.next编辑: console.log($.mobile.urlHistory.stack); 检查主页是否保留在历史记录中。 【参考方案1】:

在篡改导航时,我经常遇到同样的问题。这一切都归结为 JQM 没有在 DOM 中找到页面,尽管它在那里。您可以通过导航小部件console.log 您将看到 JQM 退出的位置以及退出原因。它通常可以从外部修复,因此无需破解 JQM。

看看最新的 JQM.js here。

    寻找这一行$.widget( "mobile.pagecontainer",

    然后找到change 方法(离得很远)。控制台日志:

            console.log("transition A")
            this._loadUrl( to, triggerData, settings );
         else 
            console.log("transition B")
            this.transition( to, triggerData, settings );
        
    

    你应该在这里,所以接下来看看load 方法,它是从_loadUrl 调用的。 Load 以 Ajax 调用或转换结束,所以如果你没有得到任何一个,你应该在这里找到原因。控制台content

        content = this._find( absUrl );
        console.log(content)
    

    如果您的页面位于 DOM 中,则应为您的页面设置内容。还有console就在下面:

        // If it isn't a reference to the first content and refers to missing
        // embedded content reject the deferred and return
        if ( content.length === 0 &&
            $.mobile.path.isEmbeddedPage(fileUrl) &&
            !$.mobile.path.isFirstPageUrl(fileUrl) ) 
            console.log("if you are here:")
            console.log("content is not found = "+ content.length === 0)
            console.log("it's NOT the first page = " + !$.mobile.path.isFirstPageUrl(fileUrl))
            console.log("it's an embedded page (i believe like a dialog, unlikely) = )"+$.mobile.path.isEmbeddedPage(fileUrl)) 
            deferred.reject( absUrl, settings );
            console.log("GOOD BYE")
            return;
        
    

    如果content 为空,请检查_find 方法,您应该在其中找到解决方法的答案。大量控制台并阅读 JQM 的 cmets!:

            var fileUrl = this._createFileUrl( absUrl ),
            dataUrl = this._createDataUrl( absUrl ),
            page, initialContent = this._getInitialContent();
    
            console.log("fileUrl ="+fileUrl)
            console.log("dataUrl ="+dataUrl)
    
            page = this.element
            .children( "[data-" + this._getNs() +"url='" + dataUrl + "']" );
            console.log(page)
    

    您会看到page 是由data-url 而不是id (!) 确定的。因此,一种解决方法可能是将正确的data-url 添加到您的页面。正确的意思是 JQM 所期望的,而不是可能正确的......另一个问题可能是dataUrl,所以请检查这是什么以及它是否是您要访问的页面的 url。通过将data-url 设置为我需要的任何内容,我设法解决了我这边的一些问题,从而确保JQM 将在DOM 中找到该页面。继续...

        if ( page.length === 0 && dataUrl && !$.mobile.path.isPath( dataUrl ) ) 
            page = this.element.children( $.mobile.path.hashToSelector("#" + dataUrl) )
                .attr( "data-" + this._getNs() + "url", dataUrl )
                .jqmData( "url", dataUrl );
                console.log(page)
                console.log(!$.mobile.path.isPath( dataUrl ));
        
    

    page 进行第二次推介,如果第一次没有成功。一定要检查第三个参数。再试一次:

            if ( page.length === 0 &&
            $.mobile.path.isFirstPageUrl( fileUrl ) &&
            initialContent &&
            initialContent.parent().length ) 
            page = $( initialContent );
            console.log(page)
            console.log($.mobile.path.isFirstPageUrl( fileUrl ))
            console.log(initialContent)
            console.log(initialContent.parent().length)
        
    

    就是这样。除非你的错误是基本的......你应该在这里找到解决方案。让我知道你卡在哪里了。我会尽力帮忙的。

编辑: 可能的解决方法:如果 JQM 的第一页存储 包含 一个主题标签,而它通常不会(因为您从 index.html 之类的东西开始,您可以通过手动删除 JQM 存储在其历史记录中的主题标签来解决这个问题 -仅限第一页。

这只需要在向后转换时完成,所以你需要一个pagebeforechange 的监听器,然后调用它:

// capture only when toPage is an object
if (typeof data.toPage !== "string") 
  // only when going back!
  if (e === undefined) 
    // only when going back to the first page
    if ($.mobile.navigate.history.initialDst &&
        window.location.hash !== "") 

      // clean url
      clean_url = window.location.href.split("#")[0];
      parsed_url = $.mobile.path.parseUrl(clean_url);

      // set in JQM
      $.mobile.navigate.history.stack[0].hash = "";
      $.mobile.navigate.history.stack[0].url = clean_url;
      $.mobile.path.documentUrl = parsed_url;
      $.mobile.path.documentBase = parsed_url;
    
  

为我工作。您可能需要稍作修改,但原则是remove the hash information on JQMs initial history entry

【讨论】:

这有帮助。我能够追查到的是:使用$.mobile.changePage("pages/login-page.html") 的页面负载弄乱了路由器。 #mainpage href 被浏览器读取为login-page.html#mainpage 中的标签,因此我的路由路径忽略了它。我不知道从这里去哪里 - 从技术上讲,它是那个页面,但骨干似乎希望它全部从同一页面引用,或者我不知道我在做什么。两者都有可能。 修复了它。它还可以让我自定义如何编写我的标签,这样他们就不必知道文件结构。 是的,很漂亮,甚至没有 hack :-)。很高兴它有帮助。 在我忘记之前,您不能在主题标签中使用 ?,因此您需要在主题标签中使用其他东西来表示 foo(我使用的是 ::

以上是关于如何使用 Backbone.js 在 changePage 后显示 JQuery Mobile 主页面的主要内容,如果未能解决你的问题,请参考以下文章

如何开始使用 Backbone.js 和 Rails 3.1

Backbone.js - 如何在模板中使用自定义模型属性?

如何使用 Backbone.Js 创建嵌套模型

如何仅使用 Javascript 在 Backbone.js 中引导集合

如何在backbone.js 中进行轮询?

如何在 Backbone.js 中设置视图的 id?