代码点火器 + jQuery(ajax) + HTML5 Pushstate:如何使用真实的 URL 进行干净的导航?

发布于 2024-11-19 10:01:03 字数 2120 浏览 4 评论 0原文

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

我想要什么:

  • 我使用 CodeIgniter 来获取干净的 URL,例如 "www.example.com/hello/world"
  • jQuery 帮助我使用 ajax,这样我就可以 .load() 附加内容
  • 现在我想使用 HTML5 功能,如 Pushstate 来 去掉 URL 中的#

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

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

例如:
一个非常基本的网站。两个链接,称为“foo”和“bar”,它们下面有一个空的 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 加载的视图,而不是整个页面。但我想通过布局和正确的控制器设置应该很容易解决这个问题。还没有太关注这个。


预先感谢您的任何帮助。 如果您有建议、想法,或者只是想简单提及一些事情,请告诉我。

问候
迪勒

I'm currently trying to build a new website, nothing special, nice and small, but I'm stuck at the very beginning.
My problems are clean URLs and page navigation. I want to do it "the right way".

What I would like to have:

  • I use CodeIgniter to get clean URLs like
    "www.example.com/hello/world"
  • jQuery helps me using ajax, so I can
    .load() additional content
  • Now I want to use HTML5 features like pushstate to
    get rid of the # in the URL

It should be possible to go back and forth without a page refresh but the page will still display the right content according to the current URL.

It should also be possible to reload a page without getting a 404 error. The site should exist thanks to CodeIgniter. (there is a controller and a view)

For example:
A very basic website. Two links, called "foo" and "bar" and a emtpy div box beneath them.
The basic URL is example.com
When you click on "foo" the URL changes to "example.com/foo" without reloading and the div box gets new content with jQuery .load(). The same goes for the other link, just of course different content and URL.
After clicking "foo" and then "bar" the back button will bring me back to "example.com/foo" with the according content. If I load this link directly or refresh the page, it will look the same. No 404 error or something.

Just think about this page and tell me how you would do this.
I would really love to have this kind of navigation and so I tried several things.


So far...
I know how to use CodeIgniter to get the URLs like this. I know how to use jQuery to load additional content and while I don't fully understand the html5 pushstate stuff, I at least got it to work somehow.
But I can't get it to work all together.
My code right now is a mess, that's the reason I don't really want to post it here. I looked at different tutorials and copy pasted some code together. Would be better to upload my CI folder I guess.

Some of the tutorials I looked at:

(max. number of links reached :/)

I think my main problem is, that everybody tries to make it compatible with all browsers and different versions, adds scripts/jQuery plugins and whatnot and I get confused by all the additional code. There is more code between my script-tags then actual html content.
Could somebody post the most basic method how to use HTML5 for my example page?


My failed attemp:
On my test page, when I go back, the URL changes, but the div box will still show the same content, not the old one. I also don't know how to change the URL in the script according to the href attribute from the link. Is there something like $(this).attr('href'), that changes according to which link I click? Right now I would have to use a script for every link, which of course is bad.
When I refresh the site, CodeIgniter kicks in and loads the view, but really only the view by itself, the one I loaded with ajax, not the whole page. But I guess that should be easy to fix with a layout and the right controller settings. Haven't paid much attention to this yet.


Thanks in advance for any help.
If you have suggestions, ideas, or simple just want to mention something, please let me know.

regards
DiLer

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

沧桑㈠ 2024-11-26 10:01:03

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

在我看来,进入 HTML5 PushState 最简单的方法是暂时忽略框架并使用最简单的状态转换:批量替换这</code> 元素。除了这些元素之外,其余的标记可能只是样板文件,尽管如果它有所不同(例如,如果您更改后端 HTML 上的类),您可以对其进行调整。

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

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

这是我们正在使用的仅有的三个文件。

这是两个 HTML 文件的代码。如果您处于处理 HTML5 功能的水平,您应该能够理解标记,但如果我没有说清楚,请发表评论,我将引导您完成它:

一.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 执行相同的操作。凉爽的。

现在,对于历史部分:

assets/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 就绪回调中定义 replacePage 来在参数中直接加载 URL 并替换 的内容>title.container 元素以及远程检索的元素。

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

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

如何扩展

这个极其基本的示例或多或少可以移植到任何网站上,因为它做了一个非常没有创意的转换:HTML 替换。我建议你可以以此为基础,过渡到更有创意的过渡。您可以做的一个示例是模拟 Github 在其存储库中的目录导航功能。这是一种需要浮动和溢出管理的中间操作。您可以从更简单的转换开始,例如将加载页面中的 .container 附加到 DOM,然后将旧容器设置为 {height: 0} 的动画。

解决您的特定“例如”

您在使用 HTML5 历史记录方面走在正确的道路上,但您需要澄清您对 /foo/bar 将包含哪些内容的想法。基本上,您将拥有三个页面://foo/bar/ 将有一个空容器 div。 /foo/ 相同,只是容器 div 中有一些 foo 内容。 /bar/foo 相同,只是容器 div 中有一些 bar 内容。现在的问题是如何通过 JavaScript 提取容器的内容。假设您的 /foo body 标记如下所示:

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

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

剩下的只是将其调整回上面的“香草”版本。如果您陷入任何特定阶段,请告诉我,我可以更好地指导您。

代码

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

I've put up a successful minimal example of HTML5 history here: http://cairo140.github.com/html5-history-example/one.html

The easiest way to get into HTML5 pushstate in my opinion is to ignore the framework for a while and use the most simplistic state transition possible: a wholesale replacement of the <body> and <title> elements. Outside of those elements, the rest of the markup is probably just boilerplate, although if it varies (e.g., if you change the class on HTML in the backend), you can adapt that.

What a dynamic backend like CI does is essentially fake the existence of data at particular locations (identified by the URL) by generating it dynamically on the fly. We can abstract away from the effect of the framework by literally creating the resources and putting them in locations through which your web server (Apache, probably) will simply identify them and feed them on through. We'll have a very simple file system structure relative to the domain root:

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

Those are the only three files we're working with.

Here's the code for the two HTML files. If you're at the level when you're dealing with HTML5 features, you should be able to understand the markup, but if I didn't make something clear, just leave a comment, and I'll walk you through it:

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>

You'll notice that if you load one.html through your browser, you can click on the link to two.html, which will load and display a new page. And from two.html, you can do the same back to one.html. Cool.

Now, for the history part:

assets/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);
    });
});

How it works

I define replacePage within the jQuery ready callback to do some straightforward loading of the URL in the argument and to replace the contents of the title and .container elements with those retrieved remotely.

The live call means that any link clicked on the page will trigger the callback, and the callback pushes the state to the href in the link and calls replacePage. It also uses e.preventDefault to prevent the link from being processed the normal way.

Finally, there's a popstate event that fires when a user uses browser-based page navigation (back, forward). We bind a simple callback to that event. Of note is that I couldn't get the version on the Dive Into HTML page to work for some reason in FF for Mac. No clue why.

How to extend it

This extremely basic example can more or less be transplanted onto any site because it does a very uncreative transition: HTML replacement. I suggest you can use this as a foundation and transition into more creative transitions. One example of what you could do would be to emulate what Github does with the directory navigation in its repositories. It's an intermediate manoever that requires floats and overflow management. You could start with a simpler transition like appending the .container in the loaded page to the DOM and then animating the old container to {height: 0}.

Addressing your specific "For example"

You're on the right track for using HTML5 history, but you need to clarify your idea of exactly what /foo and /bar will contain. Basically, you're going to have three pages: /, /foo, and /bar. / will have an empty container div. /foo will be identical to / except in that container div has some foo content in it. /bar will be identical to /foo except in that the container div has some bar content in it. Now, the question comes to how you would extract the contents of the container through Javascript. Assuming that your /foo body tag looked something like this:

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

Then you would extract it from the response data through var html = $(data).filter('.container').html() and then put it back into the parent page through $('.container').html(html). You use filter instead of the much more reasonable find because from some wacky reason, jQuery's DOM parser produces a jQuery object containing every child of the head and every child of the body elements instead of just a jQuery object wrapping the html element. I don't know why.

The rest is just adapting this back into the "vanilla" version above. If you are stuck at any particular stage, let me know, and I can guide you better though it.

Code

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

最初的梦 2024-11-26 10:01:03

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

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');

Try this in your controller:

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');
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文