前端路由
前端路由的本质是监听url变化,然后匹配路由规则,无需刷新就可以显示相应的页面,目前单页面路由主要有两种方式
- hash 模式
- history 模式
hash模式实现路由
为什么要使用hash模式:页面使用Ajax发送异步请求可以实现无缝刷新,但这种方式也存在使得浏览器的url不发生任何变化的时候就完成了请求,使得用户体验不佳,也导致了用户下次使用相同的url访问上次的页面时内容无法重新呈现的问题。hash模式是解决这个问题的途径之一。
主要通过location.hash设置hash Url,也就是url的符号#后面的值。当哈希值发生变化时,不会向服务器请求发送数据,可以通过hashchange事件来监听hash的变化,实现相应的功能
- location.hash 设置/获取hash
- hashchange事件监听url变化,解析url实现页面路由跳转
hash模式需要注意的几个点
- 散列值不会随请求发送到服务器
- 散列值会反映在浏览器url上
- 只修改浏览器的哈希部分,按下回车,浏览器不会发送任何请求给服务器,只会触发hashchange事件并且修改location.hash的值
- html a标签,设置id锚点,点击触发时,浏览器会自动设置location.hash值,同时触发hashchange事件,url上也会反映这一变化
- hash模式下,手动刷新页面不会向浏览器发送请求,不会触发hashchange事件,但是会触发load事件
示例1:location.hash触发hashchange事件
<body>
<button id="add">add hash</button>
<button id="update">update hash</button>
<script >
var i = 1;
document.querySelector("#add").addEventListener('click',()=>{
location.hash = "abc" + i++;//http://xxx.html#abc 哈希必有#
});
document.querySelector("#update").addEventListener('click',()=>{
location.hash = "efg" + i++;
});
//监听hash的变化
addEventListener("hashchange",()=>{
console.dir(location.hash);
})
</script>
</body>
效果:
示例2:锚点跳转设置hash触发hashchange事件
关于锚点跳转:
- a标签可以跳转到指定了name或者id的a标签
- a标签可以跳转到指定了id的非a标签,非a标签如果没有指定id则不可以被跳转
<body>
<a name="target1" >a name target1</a>
<div style="width: 100%; height: 500px;background-color: salmon;"></div>
<div id="target2" >div id target2</a>
<div style="width: 100%; height: 1500px;background-color: salmon;"></div>
<a href="#target1">跳转指定name的a标签</a>
<a href="#target2">跳转指定id的div</a>
<script >
//监听hash的变化
addEventListener("hashchange",()=>{
console.dir(location.hash);
})
</script>
</body>
效果
history模式实现路由
history对象
window.history属性指向history对象,它表示当前窗口的浏览历史
history对象保存了当前窗口访问过的所有页面网址,以下是常用API
-history.length:返回历史记录中的网页数量
-history.forward():前进
-history.back():后退
-history.go(num):前往相对于自身的第num个(前后取决于正负)页面
-history.state:history堆栈最上层的状态值
-history.pushState(stateObj,title,url):向当前历史记录插入一个状态值对象stateObj,并在网址后面添加url,title无实际意义
-history.replaceState(stateObj,title,url):修改history对象的当前记录
事件
-poptate:仅当浏览器动作出现时(前进、后退)才触发,pushState和replaceState方法并不会触发该事件,其回调函数参数event的state属性指向当前历史记录的state对象
history模式实现路由
history对象
window.history属性指向history对象,它表示当前窗口的浏览历史
history对象保存了当前窗口访问过的所有页面网址,以下是常用API
-history.length:返回历史记录中的网页数量
-history.forward():前进
-history.back():后退
-history.go(num):前往相对于自身的第num个(前后取决于正负)页面
-history.state:history堆栈最上层的状态值
-history.pushState(stateObj,title,url):向当前历史记录插入一个状态值对象stateObj,并在网址后面添加url,title无实际意义.
-history.replaceState(stateObj,title,url):修改history对象的当前记录
事件
-poptate:仅当浏览器动作出现时(前进、后退)才触发,pushState和replaceState方法并不会触发该事件,其回调函数参数event的state属性指向当前历史记录的state对象
history实现路由
主要通过history.pushState/replceState向当前历史记录中插入状态对象state,在浏览器前进、回退、跳转等动作发生时触发popState事件,此时可以通过解析popState事件回调函数的event参数中的state对象,或者解析当前页面url来实现路由。
建议解析url方式实现路由。如果没有在页面首次加载的时候设置pushState/replaceState,那么首页一般是没有state对象的,在执行浏览器动作时,如果回退到首页,那么当前history对象的state属性不存在,导致解析state报错
<body>
<button id="add">add state</button>
<button id="update">replace state</button>
<script>
var i = 1;
document.querySelector("#add").addEventListener('click', () => {
history.pushState({curState:i},'title','#page'+i);
i++;
});
document.querySelector("#update").addEventListener('click', () => {
history.replaceState({curState:i},'title','#page'+i);
i++
});
//监听history动作
addEventListener("popstate", () => {
console.dir(history.state.curState);
})
//监听hash的变化
addEventListener("hashchange",()=>{
console.dir('hashchange event: ',location.hash);
})
</script>
</body>
效果:
两种路由方式的差异以及需要注意的点
方式的异同
- 页面手动刷新,hash模式不会向服务器发送请求,history模式会
- hash模式下url中的哈希值不会发送到服务器,history模式url全部会发送至服务器
- 设置location.hash和pushState都不会导致浏览器刷新
- 设置location.hash的时候会触发hashchange事件和popstate事件
- 仅当pushState函数设置url参数的值为hash格式时,浏览器动作发生会触发hashchange事件,尽管location.hash值为空
- a标签锚点跳转可以设置hash,触发hashchange事件
pushState设置跨域请求
如果pushState的url为跨域网址,那么会报错.这样设计的目的是防止恶意代码让用户以为他们是在另一个网站上