CodeIgniter + jQuery(ajax)+ HTML5 pushstate:如何使用真实URL进行干净的导航?

时间:2011-07-10 02:16:29

标签: html5 url codeigniter jquery pushstate

我目前正在尝试建立一个新的网站,没什么特别的,不错的,小的,但我一开始就陷入困境。 我的问题是干净的URL和页面导航。我想以“正确的方式”做到这一点。

我想拥有什么:

  • 我使用CodeIgniter来获取干净的URL “www.example.com/hello/world”
  • jQuery帮助我使用ajax,所以我可以 .load()其他内容
  • 现在我想使用像pushstate这样的HTML5功能 摆脱URL中的#

应该可以在没有页面刷新的情况下前后来回,但页面仍会根据当前URL显示正确的内容。

还应该可以重新加载页面而不会出现404错误。由于CodeIgniter,该网站应该存在。 (有一个控制器和一个视图)

例如:
一个非常基本的网站。两个链接,称为“foo”和“bar”,下面是一个emtpy div框。 基本URL是example.com
当您单击“foo”时,URL将更改为“example.com/foo”而不重新加载,div框将使用jQuery .load()获取新内容。对于其他链接也是如此,当然不同的内容和URL 单击“foo”然后“bar”后,后退按钮将返回“example.com/foo”并显示相应内容。如果我直接加载此链接或刷新页面,它看起来会一样。没有404错误或其他什么。

想一想这个页面并告诉我你将如何做到这一点。 我真的很想拥有这种导航,所以我尝试了几件事。


到目前为止......
我知道如何使用CodeIgniter来获取这样的URL。我知道如何使用jQuery加载其他内容,虽然我不完全理解html5 pushstate的东西,但我至少让它以某种方式工作。 但我不能让它一起工作。 我现在的代码很乱,这就是我不想在这里发布它的原因。我查看了不同的教程,并将一些代码粘贴在一起。我想上传我的CI文件夹会更好。

我看过的一些教程:

(达到的最大链接数量:/)

我认为我的主要问题是,每个人都试图让它与所有浏览器和不同版本兼容,添加脚本/ jQuery插件等等,我对所有其他代码感到困惑。我的脚本标签和实际的html内容之间有更多代码。 有人可以发布最基本的方法如何在我的示例页面中使用HTML5吗?


我失败的尝试:
在我的测试页面上,当我返回时,URL会更改,但div框仍将显示相同的内容,而不是旧内容。我也不知道如何根据链接中的href属性更改脚本中的URL。是否有类似$(this).attr('href')的东西,根据我点击的链接而改变?现在我必须为每个链接使用一个脚本,这当然是坏的。 当我刷新网站时,CodeIgniter启动并加载视图,但实际上只是视图本身,我用ajax加载的视图,而不是整个页面。但我想这应该很容易修复布局和正确的控制器设置。对此还没有太多关注。


提前感谢您的帮助。 如果您有任何建议,想法或简单的想提及的话,请告诉我。

问候
DILER

2 个答案:

答案 0 :(得分:9)

我在这里提出了一个成功的HTML5历史记录示例:http://cairo140.github.com/html5-history-example/one.html

在我看来,进入HTML5 pushstate的最简单方法是暂时忽略框架并使用最简单的状态转换:批量替换<body><title>元素。在这些元素之外,标记的其余部分可能只是样板文件,但如果它有所不同(例如,如果你在后端更改HTML上的类),你可以适应它。

像CI这样的动态后端基本上是假冒特定位置(由URL标识)的数据存在,通过动态生成它。我们可以通过逐字地创建资源并将它们放置在您的Web服务器(可能是Apache)将简单地识别它们并通过它们提供它们的位置来抽象出框架的效果。相对于域根,我们将有一个非常简单的文件系统结构:

/one.html
/two.html
/assets/application.js

这是我们正在使用的唯一三个文件。

这是两个HTML文件的代码。如果你在处理HTML5功能时达到了这个水平,那么你应该能够理解标记,但如果我没有说清楚,只需发表评论,我会引导你完成它:< / p>

one.html

<!doctype html>
<html>
  <head>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.js"></script>
    <script src="assets/application.js"></script>
    <title>One</title>
  </head>
  <body>
    <div class="container">
      <h1>One</h1>
      <a href="two.html">Two</a>
    </div>
  </body>
</html>

two.html

<!doctype html>
<html>
  <head>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.js"></script>
    <script src="assets/application.js"></script>
    <title>Two</title>
  </head>
  <body>
    <div class="container">
      <h1>Two</h1>
      <a href="one.html">One</a>
    </div>
  </body>
</html>

您会注意到,如果您通过浏览器加载one.html,则可以点击two.html的链接,该链接将加载并显示新页面。从two.html开始,您可以回复one.html。凉。

现在,对于历史部分:

资产/ application.js中

$(function(){
    var replacePage = function(url) {
        $.ajax({
            url: url,
            type: 'get',
            dataType: 'html',
            success: function(data){
                var dom = $(data);
                var title = dom.filter('title').text();
                var html = dom.filter('.container').html();
                $('title').text(title);
                $('.container').html(html);
            }
        });
    }

    $('a').live('click', function(e){
        history.pushState(null, null, this.href);
        replacePage(this.href);
        e.preventDefault();
    });

    $(window).bind('popstate', function(){
        replacePage(location.pathname);
    });
});

如何运作

我在jQuery ready回调中定义replacePage,以便在参数中直接加载URL,并用远程检索的元素替换title.container元素的内容。

live调用意味着点击页面上的任何链接都会触发回调,并且回调会将状态推送到链接中的href并调用replacePage。它还使用e.preventDefault来阻止链接以正常方式处理。

最后,当用户使用基于浏览器的页面导航(后退,前进)时,会发生popstate事件。我们将一个简单的回调绑定到该事件。值得注意的是,我无法在Dive Into HTML页面上获得该版本在FF for Mac中出于某种原因工作。不知道为什么。

如何扩展

这个非常基本的例子可以或多或少地被移植到任何网站上,因为它做了一个非常无创造的过渡:HTML替换。我建议您可以将此作为基础并转换为更具创意的过渡。您可以做的一个例子是模拟Github对其存储库中的目录导航所做的事情。这是一个需要花车和溢流管理的中间件。您可以从更简单的转换开始,例如将加载页面中的.container附加到DOM,然后将旧容器设置为{height: 0}

解决您的具体“例如”

您正在使用HTML5历史记录,但您需要明确了解/foo/bar将包含的内容。基本上,您将有三个页面://foo/bar/将有一个空的容器div。 /foo将与/相同,除非容器div中包含一些foo内容。 /bar/foo相同,只是容器div中包含一些条形内容。现在,问题是如何通过Javascript提取容器的内容。假设您的/foo body标记看起来像这样:

<body>
  <a href="/foo">foo</a>
  <a href="/bar">bar</a>
  <div class="container">foo</div>
</body>

然后,您可以从回复datavar html = $(data).filter('.container').html()中提取它,然后通过$('.container').html(html)将其重新放回到父页面中。您使用filter而不是更合理的find,因为从一些古怪的原因,jQuery的DOM解析器生成一个jQuery对象,其中包含head的每个子项以及{{1}的每个子项}元素而不仅仅是包装body元素的jQuery对象。我不知道为什么。

其余的只是将其重新调整为上面的“香草”版本。如果您遇到任何特定阶段,请告诉我,尽管如此我可以为您提供更好的指导。

代码

https://github.com/cairo140/html5-history-example

答案 1 :(得分:2)

在你的控制器中试试这个:

if (!$this->input->is_ajax_request())
    $this->load->view('header');

$this->load->view('your_view', $data);

if (!$this->input->is_ajax_request())
    $this->load->view('footer');