ajax与history实现无刷新修改url

ajax

我们都知道,ajax可以实现无刷新页面获取数据,这无疑能极大地提高用户体验,但是它有一个弊端,就是通过ajax获取的内容,在页面刷新或者点击浏览器的前进和后退按钮,重新回到当前页面的时候,之前获取的内容索引丢失了,页面变回了初始状态。

ajax的弊端事例

就例如下图的分页器,点击下一页通过ajax获取内容然后改变页面的内容,当我们按了很多次下一页按钮,定位到了某一个页面,但是只要页面一刷新,页面的内容又重新定位到第一页。

image

我们想

如果我们想要在当页面刷新后,页面定位还是在当前页,或者点击浏览器的前进或者后退按钮的 时候,前进到前一页或者后退到后一页。

主角登场

这时候,html5的新增的history API主角《history.pushState》和《history.replaceState》就应该登场了:

  1. history.pushState(state,title,url):无刷新改变当前页面的url,并创建新的历史条目推入history堆栈中。

  2. history.replaceState(state,title,url):操作类似于history.pushState(),不同之处在于replaceState()方法会修改当前历史记录条目而并非创建新的条目

    • state:一个与指定网址相关的状态对象,popstate事件触发时,该对象会传入回调函数。如果不需要这个对象,此处可以填null。

    • title:新页面的标题,但是所有浏览器目前都忽略这个值,因此这里可以填null。

    • url:新的网址,必须与当前页面处在同一个域,否则会因跨域弹出错误,浏览器的地址栏将显示这个网址。

  3. popstate事件:当点击浏览器的前进或者后退按钮的时候触发。

为了更好地理解pushState和前进后退按钮对历史条目的影响,下面用数组模拟历史条目栈:

  1. 当页面刚进入的时候,历史条目为空:
var historyStack=[];
  1. 当点击触发history.pushState(),向历史条目压入一个记录:

historyStack.push('条目1');

  1. 当我们多次触发history.pushState()后:
historyState =>
[条目1,条目2,条目3,条目4]

  1. 最后一次触发后,url指针指向条目4,

  2. 当我们点击后退按钮时,指针变为指向条目3,当我们再次点击前进按钮时,指针指向变回指向条目4。

这就是pushState、浏览器按钮与历史条目之间的联系,而且每次改变条目指针后,都会触发popstate事件。

demo代码:(下面demo因为没有使用ajax与服务器交互,而是通过分页器的点击切换内容来模拟ajax的改变,这样可以直接使用这些代码进行本地测试)

html:

<body>
	<ul>
		<li class="active_li">0</li>
		<li>1</li>
		<li>2</li>
	</ul>

	<div class="active_div">
		0000000
	</div>
	<div>
		1111111
	</div>
	<div>
		2222222
	</div>
</body>

css:

*{margin: 0;padding: 0;}
li{list-style: none;display: inline-block;border: 1px solid #ccc;padding: 5px 10px;}
div{height: 200px;width: 150px;border: 1px solid #ccc;display: none;}

.active_li{background-color: #aaa;}
.active_div{display: block;}

js:

var $li=$('li');
	var $div=$('div');

	$li.on('click',function(event) {
		var his=window.history;
		var that=$(this);
		var index=that.index();
		
		$li.removeClass('active_li');
		that.addClass('active_li');

		$div.removeClass('active_div').eq(index).addClass('active_div');


		/*
			这里可以添加ajax();
		*/

		//检测是不是因为鼠标点击li触发
		if(event && /\d/.test(event.button)) {
			his.pushState(null, '', '?index='+index);
		}	

	});

	//点击返回或者前进按钮触发
	function setHistoryState() {
		
		var locaHref=location.href;
		var his=window.history;

		//初始时url没有参数,就默认为index=0;
		if(locaHref.indexOf('?')==-1) {
			his.replaceState(null, '', '?index=0');
		} else {	
			//找到当前url中index的值
			var index=returnIndex(locaHref);

			//触发指定li的点击事件
			$li.eq(index).trigger('click');
		}
		
	}

	//这个函数过滤url,返回index
	function returnIndex(str) {
		return parseInt( str.split('?')[1].split('=')[1] );
	}

	//初始化触发
	setHistoryState();

	//前进后退按钮事件
	window.addEventListener("popstate", function() {
        setHistoryState();                          
    });
    

参考文章