Topking's Blog

Seize the day, enjoy my life!

ajax分页时,点击第N页链接,回退会返回第一页解决方法

| Comments

1. 问题产生的描述

  ajax做列表数据分页时,例如,当点击跳转至第三页后,点击一个链接,跳转至详情页,再点后退就是返回第一页列表数据了,怎么能使他还是第三页?

  AJAX可以做出各种效果来,但是有一点始终是不好解决,那就是回退和刷新的问题。 由于在AJAX的异步机制,即使页面大部分被替换掉,浏览器地址栏也不会有变化,地址栏没有变化,当然就不存在历史记录了,没有历史纪录,of course就没有办法回退或者在刷新之后出现期望的内容了。   所以问题的所在就是地址栏,如何产生有效地地址呢?那首先就要明白一个URL是如何构成的:例如:

    http://www.example.com:8080/test.cgi?op=hello&cd=1#339933=ass?xa

    这个URL地址分为几个部分:

    协议:http

    主机:www.example.com

    端口:8080 (http的缺省端口是80)

    路径:/test.cgi

    search键:?op=hello&cp=1

    hash键:#339933=ass?xa

  除了hash键的更动,其他任意部分的更动都会引起页面的重载。所以只有选择hash键来保存一些状态了。

  也就是说,我们记录中间状态的存储器有了,但是该如何使用呢,这就需要解释器来重现存储器的内容了。 说的更基础原理一点(相信不懂基础原理的专业人士还是不多,而不是专业人员也没兴趣看这个),就像内存映像,多任务OS切换任务是很频繁的,在每次切换任务的时候操统要干两件事:一个就是保存上一个程序的中间状态,以方便下次加载程序;另一件事就是加载下一个程序的状态,使得这个程序能接着上次调度的结果运行。

所以,我们要做一个类似于切换程序用的解释器。这里解释器大致有三件事:1.定义存储器的使用规则,也就是说hash键主要有哪些部分组成,什么字段用在什么地方干嘛用;二:切换之前清场,将该保存的保存,该为新页面铺垫也不能漏了;三:根据新的hash键生成新的页面。

这个解释器呢,是与具体应用相关的,所以具体细节是需要研究业务的。但是在其中有个技术问题需要注意: 解释器是如何激活的?这里面涉及到IE和firefox的差异。

HASH键的改变在FireFox是会产生历史纪录的,而在IE中没这回事,所以这需要区别对待。以下是基本流程: 1)onload函数调用解释器的加载页面部分; 2)加载新页面之前生成相对应得HASH键; 3)针对FireFox可以直接更改地址栏,加载页面;针对IE要使用IFRAME,更改IFRAME的src的URL的search键为hash键,然后再由IFRAME加载的页面的onload函数调用解释器的加载页面部分,要记得一点:IFRAME的display样式设为none,要不会有些小毛小病的。

具体技术呢,大致写两页投稿是没有问题的,我还是比较懒,就不多写了。大致原理讲到了,能者就会了,不能者可以钻研一下。

忘了说了,刷新的问题实在是没有什么好招了,以上的方法虽然可以在刷新之后得到正确的页面,但是地址栏的历史纪录大概是丢了不少了,这也是没有办法的事情,有得必有失,浏览器在平衡安全和性能,使用浏览器的也需要权衡些东东。

2. 案例解决

  有了上面的理论作为支撑,也找到了在实际开发中的解决方案: 比较好的方法是用location.hash 来记录,比如在跳转至第3页的时候,先用js 保存当前的location.hash为3:

location.hash="3"; 

这样的操作不会导致页面刷新,但是却会被记录到浏览器历史里面。等到返回上一页等操作的时候,在加载初始化数据之前,先看看有没有location.hash,有的话就从里面恢复当前的页码,否则就加载第一页。

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
<script type="text/javascript">
var currentPage=1;
//location.hash会以#3形式出现;截去#,保留页数进行传递
if(location.hash){//////////////////////////////////第二步.根据页面跳转时,存在于location.hash记录的页码进行调用ajax
    currentPage=location.hash.substring(location.hash.indexOf('#')+1);
}
//使用kkpager,产生分页
template.helper('generPagination', function (pageNo, totalPage, totalRecord) {

    //生成分页控件
    kkpager.generPageHtml({
        pagerid: 'kkpager',
        pno: pageNo,
        mode: 'click', //设置为click模式
        //总页码
        total: totalPage,
        //总数据条数
        totalRecords: totalRecord,
        isGoPage: false,
        isShowCurrPage: false,
        isShowTotalPage: false,
        //点击页码、页码输入框跳转、以及首页、下一页等按钮都会调用click
        //适用于不刷新页面,比如ajax
        click: function (n) {
            //这里可以做自已的处理
            searchPro(n);
            //处理完后可以手动条用selectPage进行页码选中切换
            this.selectPage(n);
            location.hash=n;///////////////////////////第一步.在做页面点击跳转的时候,记录当前的页码
            return false;
        },
        //getHref是在click模式下链接算法,一般不需要配置,默认代码如下
        getHref: function (n) {
            return '#';
        }

    }, true);//这里true,很重要,自己扒源码看
});

//ajax搜索项目
function searchPro(pageNo) {
    $.ajax({
        url: "${path}/activity/searchProjectList",
        type: "post",
        data: {
            pageNo: pageNo, words: $('#words').val(), orderBy: $('.xmzs .p-top ul .selectblue').attr('orderBy')
        },
        dataType: "json",
        success: function (result) {
            if (result.status) {
                var html = template('searchProjectsTemplate', result.mapRet);
                $("#projectList").html(html);
                fnRadialIndicatorExec(result);
            }
        }
    });
}
</script>

Comments