最近在做一个AJAX整站的项目,主要遇到的几个问题为:
1. 局部刷新了页面,如何将url地址分享或者保存为书签?
2. 浏览器后退/前进按钮失效?
3. 搜索引擎不收录?
先说第3个问题,因为我们这个项目另有其他推广方案,所以并不对搜索引擎那么依赖,加上google是可以主动提交js内容的,相信百度日后也会支持,所以这问题并不是我要讨论的。而且我们选择使用整站AJAX是为了追求更好的用户体验。
问题1很关键,比如看某个文章,某个好友,想分享给其他人,可是AJAX局部刷新页面就好像曾经使用框架一样(某些网站管理后台),地址栏url并不改变,直接发给朋友,打开成了首页;或者看到好的内容想收藏,结果发现也只是收藏了首页。
问题2很棘手,连我自己开发的时候也感觉很不爽,页面点击多了习惯性的想后退看看,结果发现浏览器的前进/后退和javascript里面的history.go(-1)神马都是浮云……
在项目还没变的庞大的时候,我想我必须得早点解决这个问题。开始的思路是想是否能绑定事件到前进/后退按钮,没找到好办法。后来想到了定位锚,深入研究发现,确实是解决问题的关键点。
问题1和2是可以一并解决的:
解决思路:通过定位锚的变化来实现不同内容的载入。例如twitter和pip.io等都是使用此种方法。原因很简单,点击定位锚链接页面不会刷新,但是地址栏url会变化,并且可以很方便的通过javascript的location.hash获取值。同时,也顺便解决了前进/后退按钮一半的问题:因为url改变,所以至少前进/后退按钮有历史记录,可惜的是点击之后只是地址栏url改变,页面并不刷新。
这样的话,url可以进行分享和收藏到收藏夹,问题1解决,前进/后退有记录了,点击后url会改变问题2基本解决(只需要再使用一些js来处理hash)。
下面是实施技术流程思路:
首次打开页面,获取location.hash也就是定位锚的值例如#/user/xinple
,值的形式可以自己定(像urlrewrite那样)。获取之后处理分析,我这里是分成 user 和 xinple 作为两个参数通过ajax传递给php程序处理返回结果,然后修改到网页上。如果值为空就显示首页数据。
这样需要分享和被收藏的页面,可以正常的直接使用url了。
然后就是点击,我原先是每个a链接都要使用onclick事件,很麻烦,很不方便,后来在解决前进/后退按钮的时候,发现一起解决了。
前进/后退按钮点击之后,url是变化了,可惜定位锚的变化浏览器不会刷新页面,那么这时候,只需要绑定hashchange事件就行了,也就是说每当定位锚变化的时候就触发一个事件。这样不就解决问题了吗?
于是我兴奋之余,想开始着手写这个方法,但是总感觉自己写不出比较好的,然后就google了下发现原来已经有很多非常好的解决方案,甚至有的js文件gzip之后只有0.8k的大小,我自叹自己无法写出更好的,就不重复发明轮子,直接使用了。
我反复对比和测试了四五个jQuery插件(我们项目使用了jQuery,所以优先考虑插件的形式),最后下面三个脱颖而出:
jQuery hashchange event: 直接绑定事件到window.onhashchange
,并支持首次载入可以手动加载。使用简单。(目前我正在使用的就是这个。)
jQuery History: 和上面的一样也是绑定事件到window.onhashchange
,而且多了几个方法,比如修改url的定位锚,修改href里面的定位锚值等等。(注意,jQuery官网也有一个叫做jQuery history但是不一样的插件,注意区分)。(我没选择这个是因为其js文件比上面的大了一点)
jQuery History Plugin:注意区分,比上面名称多了一个plugin。这款插件,其实是另外一种用法:比如人间网虽然也是AJAX网站,也支持前进/后退,但是它url不改变。所以对于那些url不改变,但是需要支持前进/后退按钮的话,这款插件是不错的选择。其原理和上面不同,把操作放入堆栈,并且通过一个隐藏的iframe页面来产生前进/后退历史(url不改变的话,按钮是没历史记录的),加入了一个iframe隐藏页面之后,相同url也能产生记录了,具体原理可以去看作者说明。
最后,因为每次定位锚改变就能触发事件,所以<a href="#/user/xinple">阿辛</a>
不需要再使用onclick事件了,点击之后url定位锚变化了,自然就触发了上面hashchange事件,然后我把数据调用在这里面完成就搞定了。从此可以和普通网站那样写链接做页面了。另外,由于定位锚被当成不同页面链接用了,其原来用来定位的功能我们可以通过自行修改其偏移值来实现,上下滚动反而更柔滑,方法见我以前的文章《定位锚平滑滚动jQuery代码》
至此,问题解决,记录下来,希望多少能给人一点帮助,至少也花了我一天多时间来研究和实践。