javascript的地址栏魔法

在咱还是初中生的时候,做论坛非常流行“换页不断曲”的页面播放器,简单点说就是框架页面,上面一个Frame是论坛的网址,下面是播放器。

这样做有一个非常明显的弊端:地址栏不会随着论坛页面变化而改变。这是一件非常伤的事情……存书签不方便了,如果你自己的网站有防止被嵌入框架的代码(比如马铃薯、肥鹅微薄就这么干)这种方法会不生效,还有:我初中的时候框架页这种技术就很low了,更别提现在。

所以我们需要一个更加高大上的方法,高大上到低版本IE都无法兼容(σ≧∀≦)σ (在我眼里兼容性一直都是用来吃的,别想太多(゚∀。)

基础知识

我的这个博客就是用了新技术实现了Ajax动态切换内容但是不跳页,至于播放器,还正在实现。一想起要用js写个音量调节滚轮就觉得完全没力气写下去 _(¦3」∠)_

废话不多说了,先看一下我们所需要知道的知识:

获得页面地址栏信息

Window.location对象,用来存储和URL相关的一切信息,乃可以自己执行一下下面的这段代码体验一下这个对象中究竟包含了多少玩意:

1
console.log(window.location)

我们只需要其中的一个:window.location.href,存储的是一个字符串,内容是地址栏的地址。

得到地址栏后可以使用split方法对内容进行切分,比如我想要得到井号后面的内容,可以这么做:

1
console.log(window.location.href.split("#")[1])

split是从String上继承下来的方法,因为太过基础我就不在这里讲太多了,不懂的话可以参考这里。

History API

接下来,说说两个兼容性很差的东西:HTML5的History API。

这货就是能操作地址栏的魔法!(不是Magic code,别想太多……)

一共介绍两个方法一个事件:

先说两个方法:

1
2
3
4
//向历史记录中添加一个地址
history.pushState(「深拷贝对象」, 「新页面的Title」, 「需要显示在地址栏的URl」)
//替换当前历史记录信息
history.replaceState(「深拷贝对象」, 「新页面的Title」, 「需要显示在地址栏的URl」)

深拷贝对象是啥呢,综合犀牛书(Javascript权威指南 第六版 P664 第三行第一个句号往后,包括标题)、MDN、维基百科的信息和公子的讲解,我来做个比较粗浅的解释:如果这个对象能JSON.stringify就代表它能被序列化、能被深拷贝(눈_눈)。

所谓的深拷贝就是递归复制下某一对象的完整信息,要知道我们在js中如果简单的做下面的操作:

1
2
var a = {"baka":"kitkom"} /*nxt line*/
, b = a;

b所包含的内容并不是a的内容,而是指向a的一个记号,也就是说我们在改变a.baka的时候,b.baka也会随之变化。

深拷贝(也称结构性复制)不同于简单的赋值操作,它完整的拷贝下了这个对象的全部信息;在你重新对原始对象进行操作的时候深拷贝对象是不会跟着变的。

上面的东西如果你看不懂的话可以忽略……

在进行history.push(replace)State操作的时候,第一个对象会被深拷贝,并存储下来。这样在后退操作的时候,可以读取这个深拷贝对象中的信息,将里面的信息重新放回页面。

这样问题就来了,如果你在pushState的第一个参数中填入了一个不能被序列化的对象(比如Element,jQuery对象,Function对象)那么就会报错。

一般人是不会傻缺到要保存一个function的状态,但是试图去保存Element对象或者jQuery对象这种误操作是可能存在的,不要这么做。

这是我之前写代码的时候遇到的问题,所以简单的说一嘴(∑(ι´Дン)ノ哪里简单啊。

不管怎么说,大概就是这么个操作思路ლ(╹◡╹ლ)。

恩,两个方法讲完了,再讲一个事件:popstate

当发生了后退操作、前进操作的时候,且push(replace)State所创建的历史记录序列没到尽头的情况下,会触发popstate事件;popstateevent有一个最重要的属性:state,返回深拷贝对象。其余的属性我觉的没啥用,不介绍了(´ω)人(´ω)。

在页面加载时,部分浏览器的部分版本会触发popstate事件(目前我知道的浏览器都不会触发但是火狐的某些版本会(눈_눈))。

—-这句话很重要—->所以安全的做法是在页面准备好之后立刻对页面进行一次replaceState操作。<—-这句话很重要—-

范例代码

下面我们是不是应该举个栗子?下面的代码是我博客的代码(有删减,注释在对应代码上方或右侧)。

切换页面的操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//包含data-ljax的a对象被点击的时候执行下面的操作
$("body").delegate("a[data-ljax],*[data-ljax] a", "click", function(event) {

var url = $(this).attr("href"); //获得目标页面的URl
$("body").addClass("blur"); //css里面有设计,当body的class是blur的时候显示加载中

//通过get方法取得页面
$.get(url, function(data) {
//通过正则解析出返回数据的标题
var title = /<title>([\s\S]*?)<\/title>/gmi.exec(data)[1] /*nxt line*/
//存储旧页面#main的HTML内容
, copyObject = $("#main").html() /*nxt line*/
//正则解析返回数据的正文内容(#main中的HTML代码)
, content = /<section id="main">([\s\S]*?)<\/section>/gmi.exec(data)[1]

//覆盖Title
$("title").html(title);
//覆盖#main的内容,替换为新的返回数据
$("#main").html(content);

//隐藏加载中动画
$("body").removeClass("blur");

//向浏览器记录中追加一条记录,并进行深拷贝
history.pushState(copyObject, title, url);
});

//防止默认的页面调转行为
event.preventDefault();
});

当浏览器后退的时候进行的操作:

1
2
3
window.onpopstate = function(event) {
$("#main").html(event.state);
};

没了,看我码了这么多字,出来的代码却这么少是不是特别不平衡(σ′▽‵)′▽‵)σ。

History 其他方法

最后的最后,History还有back(后退)forward(前进),go(参数为正表示前进,负表示后退)这三个方法,参数为想要跳的步骤,给不知道的同学简单说下,恩。

具体用法:

1
history.go(-2);

大概就是这么简单。

那么今天的介绍就到这里=3=~。