实现前端路由的两种方式及其差异

前端路由

前端路由的本质是监听url变化,然后匹配路由规则,去做一些dom的增删或替换,无需刷新就可以显示相应的页面,目前单页面路由主要有两种方式

  • 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模式会, 后者会导致404问题,需要后端配置,或者开启NGINX配置
  • hash模式下url中的哈希值不会发送到服务器,history模式url全部会发送至服务器
  • 设置location.hash和pushState都不会导致浏览器刷新
  • 设置location.hash的时候会触发hashchange事件和popstate事件
  • 仅当pushState函数设置url参数的值为hash格式时,浏览器动作发生会触发hashchange事件,尽管location.hash值为空
  • a标签锚点跳转可以设置hash,触发hashchange事件

pushState设置跨域请求

如果pushState的url为跨域网址,那么会报错.这样设计的目的是防止恶意代码让用户以为他们是在另一个网站上

posted @ 2020-03-16 09:40  IslandZzzz  阅读(1834)  评论(0编辑  收藏  举报