让 Backbutton 在单页网站中工作并实现“说话”的 URL

Posted

技术标签:

【中文标题】让 Backbutton 在单页网站中工作并实现“说话”的 URL【英文标题】:Getting Backbutton to work in single page website and implementing "speaking" URLs 【发布时间】:2014-02-20 23:08:42 【问题描述】:

我有一个单页网站,希望实现以下目标:

    后退按钮就像普通网站一样工作

    而不是说,

www.mysite.com/index.php?p=#this-is-a-great-product

我想要这个网址

www.mysite.com/this-is-a-great-product

虽然后退按钮仍然正常工作。

关于 1.) 我使用我发现的以下代码,效果很好:

<!-- Getting BackButton to  work properly -->
<script type="text/javascript">
var times = 0;
function doclick() 
    times++;

function doclick() 
    times++;
    location.hash = times;

window.onhashchange = function()      
    if (location.hash.length > 0)         
        times = parseInt(location.hash.replace('#',''),10);     
     else 
        times = 0;
    

</script>

...但当然它只是将任何锚点更改为 /#1,然后 /#2 等等以使后退按钮起作用。但由于我不是程序员,我不知道如何更改它……:(

关于 2.) 我可以在 htaccess 中添加这个:

>RewriteEngine On
>RewriteRule ^([^/.]+)/?$ /index.php?page=$1

这会将 /index.php?p=products 更改为 /products。

那么我该如何更改上面的代码(在 1 下),所以它不会将所有锚点更改为 #1、#2 等,而是引用/使用我在 2 下实现的 url,例如

www.mysite.com/this-is-a-great-product

并且(可能是一个非常愚蠢的问题,但一个非常重要的问题) - 鉴于我在我的网站上只使用 新的 url 链接 - 这有什么危险吗?仍然可能以任何方式导致重复的内容?

关于这一点,我是否应该(出于这个原因或任何其他原因)使用 rel canonical link=index.php 将我的单页 index.php 对其自身进行区分?

提前非常感谢!

【问题讨论】:

【参考方案1】:

如前所述,您将需要使用 html5 History API。请注意,这个 API 相对较新,因此浏览器支持是一个问题。在撰写本文时,大约 71% 的全球 Internet 用户支持它(有关浏览器支持信息,请参阅 http://caniuse.com/#feat=history)。因此,您需要确保为此有一个备用解决方案。您可能想要使用旧的 #!在采用 HTML 5 History API 之前流行的解决方案。

如果您使用历史 API 将 example.com/#!settings 替换为 example.com/settings 并且用户将更好的 URL 加入书签,那么当他们去访问它时,他们的浏览器将向服务器发出请求/settings(实际上并不存在于 Web 服务器的上下文中)。因此,您需要确保您的 Web 服务器具有一些重定向规则(即 RewriteEngine),以便它可以获取漂亮的 URL 并将它们重定向到 #!版本(然后如果用户的浏览器支持历史 API,它可以用漂亮的 URL 替换它)。

如果您自己编程不太习惯,我建议您使用一个可以为您完成大量工作的 JavaScript 库。我做了一些快速搜索,发现了以下内容,尽管可能有更好的:https://github.com/browserstate/history.js

【讨论】:

【参考方案2】:

基本上,我在jsfiddle 上创建了一个小型原型,它跟踪通过 ajax 调用访问的所有 url。

还包含来回访问链接的导航。

实际工作原理:

我创建了一个名为history 的全局数组,它按顺序跟踪通过ajax 访问的所有url。 还定义了一个全局 index,用于在来回导航 history 数组中的链接时跟踪访问的 url。 jsfiddle 的底部有History section,它通过捕获链接名称并按照访问顺序发布链接来显示访问链接的顺序。

JS 代码:

$(function () 
var history = [];
var index = 0;
$('.links').on('click', function () 
    $('#history').append($(this).text());
    var address = $(this).attr('data-ref');
    index += 1;
    history[index] = address;

    $('.links').attr('disabled', 'disabled');
    loadExternalPage(address);
    console.log('list:' + history);
);

$('#back').on('click', function () 
    console.log(index);
    index -= 1;
    console.log(index);
    console.log(history[index]);
    loadExternalPage(history[index]);
);

$('#forward').on('click', function () 
    console.log(index);
    index += 1;
    console.log(index);
    console.log(history[index]);
    loadExternalPage(history[index]);
);

var loadExternalPage = function (address) 
    console.log(history[index]);
    $('#result-section').load(address, function () 
        console.log('data-loaded');
        $('.links').removeAttr('disabled');
    );
;
);

现场演示@JSFiddle:http://jsfiddle.net/dreamweiver/dpwmcu0b/8/

注意:此解决方案远非完美,因此不要将其视为最终解决方案,而是将其用作构建的基础

【讨论】:

小提琴不再可用:( @JackMiller 现有的 jsfiddle 链接已损坏,现在已更新,快乐编码:)【参考方案3】:
    关于在浏览器左上角按钮中使用 BACK 和 FORWARD 功能:

原则上,只要您在浏览器上为以前访问过的网页使用现有的存储对象(堆栈),这没有什么大问题。这个对象是 history 对象,你可以通过右键单击并选择“Inspect”,然后选择“Console”选项卡,然后输入 window.history em> 并输入。 查看 Pro Java For Web Developers (Frisbee) 的浏览器对象模型 (BOM) 部分,了解历史对象的背景。 (只需几页,易于阅读,别担心。)请记住,在此过程中,您存储的是您移动到的新页面,而不是您所在的旧页面离开!

对于一个简单的 SPA 示例,请查看此示例。 codepen.io/tamjk/pen/NWxWOxL

    关于 URL,history 对象用于将新页面状态加载到历史堆栈中的方法,即 pushState(...),有一个可选的第三个参数,用于关联一个存储的每个网页的虚拟 URL。 就个人而言,当我第一次整理 BACK 和 FORWARD 函数时,我没有使用虚拟 URL,因为浏览器被它们混淆了,我已经足够使用前两个参数来整理历史序列了,即
状态对象 - 一个 JSON 包含足够的数据来重新创建存储的页面 页面的标题我希望您也可以使用虚拟 URL,但正如他们所说,我会将其留给学生作为练习。

但你可以根据需要添加新页面的 URL。

在上面的示例中,对于状态对象,我只使用了页面导航链接及其内容元素的 ID。 对于标题,我在每次更改页面时以编程方式更改了 HTML 的页面标题元素。在注意到浏览器根据 HTML 代码中的 title 元素列出了之前的页面后,我这样做了。 不幸的是,由于 CodePen 的系统不允许,当您右键单击浏览器的 BACK 和 FORWARD 按钮时,该标题不会显示在 CodePen 上。但它会显示在您自己的网站上。

重要的是,无论您使用导航栏链接导航时使用何种方法存储当前网页状态,当您使用后退或前进按钮到达浏览器历史记录时,都不要将页面状态添加到浏览器历史记录中。否则,您的历史堆栈将重复返回条目并删除条目。 在 CodePen 中,这是通过将 addToHistory(..) 函数与 switchPage(...) 函数的范围分开来实现的。这允许您在普通导航栏导航和浏览器 BACK/FORWARD 导航中使用 switchPage 功能。 switchPage(...) 的第三个参数是一个布尔值,指示页面是否存储在历史记录中。

无论如何,这只是让您入门的东西。

【讨论】:

以上是关于让 Backbutton 在单页网站中工作并实现“说话”的 URL的主要内容,如果未能解决你的问题,请参考以下文章

会话无法在 chrome 中工作并在 Firefox 中工作

代码在调试中工作并从 Visual Studio 运行,但是发布模式会出错

ctypes.cast 在 python2 中工作并在 python3 中抛出 ArgumentError

React js:在单页应用程序中呈现多个索引 html

错误无法在laravel中工作并在数据库中给出列错误

如何在单页应用程序 (SPA) 的特定页面中隐藏对讲聊天小部件?