8

我有以下测试应用程序: http: //dev.driz.co.uk/ajax/

您可以单击链接以使用 jQuery AJAX 在其他页面中加载,并且有两种类型,globalTabs 和 localTabs 将内容加载到不同的面板中。注意:每个页面实际上是整个页面,但我们只使用 jQuery find 方法获取我们想要的内容。

为了增强这一点,我使用了 HTML5 History API(History.js for cross-browser)。

标题和网址更改得很好,历史堆栈被成功推送,当我使用后退和前进按钮时,网址和标题确实恢复了。

现在复杂的部分是从以前的状态加载回内容,更复杂的是加载正确的类型,例如全局或本地 ajax。为了实现这一点,我想我需要将数据和类型都传递给推送状态,以便它可以再次用于 popstate ......

谁能帮我指出正确的方向?我已经完成了所有第一部分的工作,只是将 ajax 类型传递给 pushState,然后通过 popstate 更改重新使用它。

为了改进这一点,我将其重写如下,以显示我传递类型和数据的计划:

注意:大写的 History 是因为我使用 History.js

var App = {

    init: function() {

        $(document).ready(function() {

            $('.globalTabs li a').live('click', function (e) {
                e.preventDefault(); 
                App.globalLoad( $(this).attr('href') );
            }); 

            $('.localTabs li a').live('click', function (e) {
                e.preventDefault();
                App.localLoad( $(this).attr('href') );
            });

        });

        window.addEventListener('popstate', function(event) {

            // Load correct content and call correct ajax request...

        });

    },

    localLoad: function ( url ) {

        $.ajax({
            url: url,
            success: function (responseHtml) {
                $('.localContent').html($(responseHtml).find('#localHtml'));

                $data = { $(responseHtml).find('#localHtml'), 'local'};

                History.pushState($data, $(responseHtml).filter('title').text(), url);
            }
        });

    },

    globalLoad: function ( url ) {

        $.ajax({
            url: url,
            success: function (responseHtml) {
                $('.mainContent').html($(responseHtml).find('#globalHtml'));

                $data = { $(responseHtml).find('#globalHtml'), 'global'};

                History.pushState($data, $(responseHtml).filter('title').text(), url);
            }
        });

    }

};

App.init();

更新:为了澄清这个问题,这是我寻求帮助的两个问题。

1.) 获取处理 ajax 请求的后退和前进按钮,以便它们将正确的数据加载回内容区域。

2.) 将内容加载到正确的区域,同时使用 pushState 方法传递内容,以便它知道它是全局 div 还是本地 div 请求。

4

2 回答 2

12

数据对象是错误的,这就是你遇到这个问题的原因。对象由键值对定义:

object = {key:'value'};
$data = { text:$(responseHtml).find('#globalHtml'), type:'global', url:'the_url'};

不是

$data = { $(responseHtml).find('#globalHtml'), 'global'};

使用对象定义,您将使用 History.getState() 取回数据

History.Adapter.bind(window,'statechange',function(){
    var data = History.getState().data;
    if(data){
        var html = data.text;
        var type = data.type;
        var type = data.url;
        if(html && type){
            if(type == 'global'){
                // just change html
                $('.mainContent').html(html);
                // call the App object's function
                if(url) App.localLoad(url);
            }else{
                $('.localContent').html(html);
            }
        }
    }
})

笔记:

  • 当 statechange 事件被触发时,如果存在任何数据,它将触发 ajax 调用
  • 模拟ajax调用而不只是改变标题,我认为这将涵盖它

编辑

  • 数据对象实际上取自 History.getState().data 而不是 History.getState()
  • 向存储的对象添加了另一个参数以保留 url
  • 使用 url 和类型,您可以调用与 onClick 事件中相同的函数

问题:

未捕获的 TypeError:将循环结构转换为 JSON

一个对象在某处引用自己;因此消息“循环结构”。这意味着您正在尝试对具有自身引用的对象进行字符串化,这通常发生在 DOM 元素中。你真的应该考虑改变

$data = { $(responseHtml).find('#localHtml'), 'local'};

至:

$data = { html:$(responseHtml).find('#localHtml').html(), type:'local'};

注意对象的键(html 和类型)和 html 函数调用 (.html()),这样您就不会发送不必要的数据,只发送 html。如果您需要在将其作为 DOM 对象加载时使用 html 数据,请使用以下命令:

var DOM_Element_loaded = $('<div>').html(html_loaded);

现在您可以使用 DOM_Element_loaded 在加载的 html 中搜索/操作数据,而无需将其附加到正文。

于 2012-08-25T07:45:26.990 回答
0

注意:这实际上更像是评论而不是答案,但是您可以通过答案响应获得更好的语法突出显示。

这就是我遇到这个问题时所做的。如果我没记错的话,这可以防止双重请求问题。

window.onpopstate = function(event) {
  if (event.state && event.state.initialHref) {
    // make an AJAX request
    // URL for AJAX request is event.state.initialHref
  }
}

当我使用history.pushState()/history.replaceState()时,我initialHref在对象中为第一个参数定义一个属性。我为此值使用绝对 URL,而不是相对 URL。

于 2012-08-31T19:24:16.133 回答