前端:将网站打造成单页面应用SPA

转载 2015年07月31日 11:22:34

前言

不知你有没有发现,像Github、百度、微博等这些大站,已经不再使用普通的a标签做跳转了。他们大多使用Ajax请求替代了a标签的默认跳转,然后使用HTML5的新API修改了Url,你可以在F12的Network面板里发现这个秘密。
这项技术并没有特别标准的学名,大家都称呼为Pjax,意为PushState + Ajax。这并不完全准确,因为还有Hash + Ajax等方法,但为了方便,我们下文还是统称为Pjax。

为什么要这么做?

Pjax是一个优秀的解决方案,你有足够多的理由来使用它:

可以在页面切换间平滑过渡,增加Loading动画。
可以在各个页面间传递数据,不依赖URL。
可以选择性的保留状态,如音乐网站,切换页面时不会停止播放歌曲。
所有的标签都可以用来跳转,不仅仅是a标签。
避免了公共JS的反复执行,如无需在各个页面打开时都判断是否登录过等等。
减少了请求体积,节省流量,加快页面响应速度。
平滑降级到低版本浏览器上,对SEO也不会有影响。

原理呢?

Pjax的原理十分简单。
1. 拦截a标签的默认跳转动作。
2. 使用Ajax请求新页面。
3. 将返回的Html替换到页面中。
4. 使用HTML5的History API或者Url的Hash修改Url。

HTML5 History API

我们来看看HTML5在History里增加了什么:

history.pushState(state, title, url)
pushState方法会将当前的url添加到历史记录中,然后修改当前url为新url。请注意,这个方法只会修改地址栏的Url显示,但并不会发出任何请求。我们正是基于此特性来实现Pjax。它有3个参数:

state: 可以放任意你想放的数据,它将附加到新url上,作为该页面信息的一个补充。
title: 顾名思义,就是document.title。不过这个参数目前并无作用,浏览器目前会选择忽略它。
url: 新url,也就是你要显示在地址栏上的url。
history.replaceState(state, title, url)
replaceState方法与pushState大同小异,区别只在于pushState会将当前url添加到历史记录,之后再修改url,而replaceState只是修改url,不添加历史记录。

window.onpopstate 事件
一般来说,每当url变动时,popstate事件都会被触发。但若是调用pushState来修改url,该事件则不会触发,因此,我们可以把它用作浏览器的前进后退事件。该事件有一个参数,就是上文pushState方法的第一个参数state。

一个实例:

这里我们以daipig为例,打开daipig,地址栏是http://www.daipig.com 。接下来打开F12 Console,输入:

history.pushState({ a: 1, b: 2 }, null, “http://www.daipig.com/abcdefg“);
可以发现,url已经变成我们输入的url了,但页面并没有刷新,也没有发出任何请求。现在再输入history.state,就可以看到我们刚刚传过来的第一个参数state了。
这时点击后退,url会回到www.daipig.com,同样是没有刷新。只不过后退的时候其实是触发了window.onpopstate事件的。

详细文档可以查阅MDN: https://developer.mozilla.org/zh-CN/docs/DOM/Manipulating_the_browser_

怎么完整的实现Pjax?

Pjax的原理上文已经讲了,并不复杂。我实现了一个比较粗糙的Pjax库,已经能满足不少需求,如果你有兴趣,可以上Github帮忙完善一下代码。地址是:https://github.com/Coffcer/coffce-pjax
完整的代码见Github,这里我们只谈需要注意的一些地方。

匹配选择器

要实现Pjax,难免就会有匹配选择器的需求。你需要判断当前点击的元素,是否匹配指定选择器。这里我给出一个兼容至IE8的解决方法:

function matchSelector(element, selector) {
var match =
document.documentElement.webkitMatchesSelector ||
document.documentElement.mozMatchesSelector ||
document.documentElement.msMatchesSelector ||

    function(selector, element) {



        if (element.tagName === selector.toUpperCase()) return true;

        var elements = document.querySelectorAll(selector),
        length = elements.length;

        while (length--) {
        if (elements[length] === this) return true;
        }

        return false;
    };


matchSelector = function(element, selector) {
    return match.call(element, selector);
};

return matchSelector(element, selector);

}
matchSelector(document.getElementById(“abc”), “#abc”);
matchSelector(document.querySelector(“a”), “p”);
在现代浏览器上,优先使用原生的matchesSelector方法来判断,在IE8及以下的浏览器里,循环document.querySelector的结果集,依次对比。
这个方法利用了闭包,然后重写自身,只有在第一次调用时需要判断加哪个前缀执行哪个方法,其后都是调用了闭包的match函数。

不支持HTML5 PushState的浏览器怎么办?

IE6到IE9是不支持pushState的,要修改Url,只能利用Url的Hash,也即是#号。
你可以随意找个网站试一下,在url后面加上#号和任意内容,页面并不会刷新。此时点击后退也只会回到上一条#号,同样不会刷新。
那么我们只需把pushState(新url)换成localtion.hash = 新url,把onpopstate事件换成onhashchange事件就可以兼容IE了。
QQ音乐,网易云音乐等就是使用这种方式。

现成的库

我简单实现了一个比较粗糙的Pjax库,地址是:https://github.com/Coffcer/coffce-pjax ,欢迎PR和Star。

本文由 Easy 第一时间收藏到GET,原文来自 → segmentfault.com

前端:将网站打造成单页面应用SPA

摘要:不知你有没有发现,像Github、百度、微博等这些大站,已经不再使用普通的a标签做跳转了。他们大多使用Ajax请求替代了a标签的默认跳转,然后使用HTML5的新API修改了Url,你可以在F12...
  • gongzhuxiaoxin
  • gongzhuxiaoxin
  • 2016年10月01日 19:09
  • 1081

前端:将页面打造成单页面应用SPA

前言 不知你有没有发现,像Github、百度、微博等这些大站,已经不再使用普通的a标签做跳转了。他们大多使用Ajax请求替代了a标签的默认跳转,然后使用HTML5的新API修改了Url,你可以在F1...
  • u013063153
  • u013063153
  • 2016年10月25日 16:00
  • 1940

SPA单页WEB应用博客开始第一篇--2015-03-28

入职新公司后,工作从后端转到前端,以后的工作也围绕前端,因此开了一个新的栏目记录下学习前端的一些知识点和总结。同事也是对刚买的新书【单页WEB应用JavaScript从前端到后端】的读书笔记。从后端到...
  • ivan0609
  • ivan0609
  • 2015年03月28日 16:00
  • 1775

前端:将网站打造成单页面应用SPA(一)

原文地址:https://segmentfault.com/a/1190000002920768 前言 不知你有没有发现,像Github、百度、微博等这些大站,已经不再使用普通的a...
  • u013063153
  • u013063153
  • 2016年09月12日 16:12
  • 587

前端:将网站打造成单页面应用SPA

摘要:不知你有没有发现,像Github、百度、微博等这些大站,已经不再使用普通的a标签做跳转了。他们大多使用Ajax请求替代了a标签的默认跳转,然后使用HTML5的新API修改了Url,你可以在F12...
  • gongzhuxiaoxin
  • gongzhuxiaoxin
  • 2016年10月01日 19:09
  • 1081

将网站打造成单页面应用SPA(一)

前言 不知你有没有发现,像Github、百度、微博等这些大站,已经不再使用普通的a标签做跳转了。他们大多使用Ajax请求替代了a标签的默认跳转,然后使用HTML5的新API修改了Url,你可以在F1...
  • wht15501032502
  • wht15501032502
  • 2017年06月03日 12:28
  • 218

将网站打造成单页面应用SPA(Single Page Application)

摘要:不知你有没有发现,像Github、百度、微博等这些大站,已经不再使用普通的a标签做跳转了。他们大多使用Ajax请求替代了a标签的默认跳转,然后使用HTML5的新API修改了Url,你可以在F12...
  • babybk
  • babybk
  • 2017年02月10日 10:48
  • 545

将网站打造成单页面应用SPA

前言 不知你有没有发现,像Github、百度、微博等这些大站,已经不再使用普通的a标签做跳转了。他们大多使用Ajax请求替代了a标签的默认跳转,然后使用HTML5的新API修改了Url,你可以在...
  • Truong
  • Truong
  • 2017年06月09日 17:01
  • 122

前端:将页面打造成单页面应用SPA

前言 不知你有没有发现,像Github、百度、微博等这些大站,已经不再使用普通的a标签做跳转了。他们大多使用Ajax请求替代了a标签的默认跳转,然后使用HTML5的新API修改了Url,你可以在F1...
  • u013063153
  • u013063153
  • 2016年10月25日 16:00
  • 1940

Alpaca-Spa 前端单页面框架

Alpaca-spa.js是一款轻量的前端JS框架,提供前端路由功能,前端视图渲染功能,前端套页面功能。目的是用来提高web项目的开发效率,前后端分离开发,同时使前端代码结构更加整洁。    ...
  • spring_cheng
  • spring_cheng
  • 2017年07月13日 09:23
  • 529
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:前端:将网站打造成单页面应用SPA
举报原因:
原因补充:

(最多只允许输入30个字)