前端框架使用ajax请求数据,使得用户可以不刷新页面,就能得到新的数据。
但有些场景,ajax请求了几次后(比如,跳转不同 page),用户想使用浏览器返回按钮返回刚才浏览的某个 page,那怎么实现?
DEMO: https://tianya.herokuapp.com/articles/ty556242?page=1
效果:
1)HTML5 提供 history.pushState() and history.replaceState()
methods, 允许你添加和修改 history entries.
(以下例子请 git clone https://github.com/moling3650/mblog-Flask.git,感谢作者:moling3650)
功能:
用户进入Manage页面时,history.replaceState来同步替换地址栏的地址(不增加新的history entity)
history.state 从 null -> Object {pg_his: "1"}
用户点击pagination页码时,会触发 ajax请求,这时我们加入 history.pushState来同步修改地址栏的地址(增加新的history entity)
history.state (add) Object {pg_his: "2"}
JS: manage.js
var vm = new Vue({ el: '#vm', data: { table: location.pathname.split('/').pop(), items: [], page: null, models: { 'users': {'name': '名字', 'email': '电子邮箱'}, 'blogs': {'name': '标题', 'user_name': '作者'}, 'comments': {'user_name': '作者', 'content':'内容'}, 'oauth': {'id': 'ID', 'user_id': '用户ID'}, 'logs': {'id': 'ID', 'ip': '用户IP'}, }, }, computed:{ fields: function () { return this.models[this.table]; } }, ready: function () { var pg = getUrlParams('page'); pg = pg || 1 history.replaceState({pg_his: pg}, "", this.table+"?page="+pg) // 打开首页时,/blogs -> replace 为 /blogs?page=1 this.getItemsByPage(pg, getUrlParams('size')); }, methods: { getItemsByPage: function (page, size) { var self = this; getJSON('/api/' + this.table, { page: page || '1', size: size || '10' }, function (err, data) { self.items = data.items; self.page = data.page; }) }, vaildPage: function(i) { return (i > 1) && (Math.abs(i - this.page.index) < 3); }, gotoPage: function (page, back) { if (! back) { history.pushState({pg_his: page}, "", this.table+"?page="+page); // /logs?page=3 } return this.getItemsByPage(page, this.page.limit); } } });
HTML: bootstrap-manage.html
<ul class="pagination"> <li :class="{'active': page.index===1}"> <a href="javascript:void(0)" v-on:click="gotoPage(1, false)" v-text="1">a> li> <li class="disabled" v-if="(page.index - 1) > 3"><span>...span>li> <li :class="{'active': page.index===i}" v-for="i in page.last | filterBy vaildPage"> <a href="javascript:void(0)" v-on:click="gotoPage(i, false)" v-text="i">a> li> <li class="disabled" v-if="(page.last - page.index) > 3"><span>...span>li> <li :class="{'active': page.index===page.last}" v-if="page.last > 1"> <a href="javascript:void(0)" v-on:click="gotoPage(page.last, false)" v-text='page.last'>a> li> ul>
2)点击浏览器返回按钮,则响应事件:window.onpopstate
event
为了跟 点击 pagination页码 区分,加入布尔值 (back)
JS:
window.onpopstate = function(event) { var state = event.state if (state===null) { return null; } var pg = state.pg_his console.log("location: " + document.location + ", state: " + JSON.stringify(state) +"length:"+window.history.length) vm.gotoPage(page=pg, back=true) };