美文网首页Web前端之路让前端飞Web 前端开发
说一说不依赖服务器的前端路由

说一说不依赖服务器的前端路由

作者: 7天苹果 | 来源:发表于2017-08-23 10:54 被阅读242次

    什么是前端路由?

    所谓的前端路由,拥有这样一种能力:客户端浏览器可以不依赖服务端,根据不同的URL渲染不同的视图页面。

    为什么要有前端路由?

    首先,它的出现无疑减轻了服务器端的压力。特别是对于一个比较复杂的应用来讲,或者更确切的说,对于拥有一个复杂路由系统的应用来说,服务器端需要为每一个不同的url执行一段处理逻辑在高并发的情况下实在有点不堪重负;其次,页面的切换可以不需要刷新整个页面了,没有网络延迟,没有闪烁刷新,提升了用户体验。

    前端路由实现方式

    首先我们知道了前端路由是不依赖服务器的,所以我们在前端需要做的就是:

    • 在不改变页面的前提下实现url的变化
    • 捕捉到url的变化以便执行页面替换

    在不改变页面的前提下如果实现url的变化?这里有两种方式:

    1. 使用url中的hash字段
    2. 使用html5的history API

    hash方式

    了解http协议就会知道,url的组成部分有很多,譬如协议、主机名、资源路径、查询字段等等,其中包含一个称之为片段的部分,以“#”为标识。例如:www.gmail.com/text/#123打开控制台,输入 location.hash,你可以得到当前url的hash部分(如果当前url不存在hash则返回空字符串)。
    比如:

    //https://www.nowcoder.com/discuss/33880?type=2&order=0&pos=57&page=1
    console.log(location.hash);    //''
    

    接下来,输入 location.hash = '123',会发现浏览器地址栏的url变了,末尾增加了’#123’字段,并且,页面没有被重新刷新。很显然,这很符合我们的要求。

    history API

    html5引入了一个history对象,包含了一套访问浏览器历史的api,可以通过window.history访问到它。

    这里我们要用的是它的两个api方法:pushStatereplaceState

    history.replaceState(dataObj, title, url);
    history.pushState(dataObj, title, url);
    

    若上所示,它们接收完全相同的参数,都是对浏览器的历史栈进行操作,将传递的url和相关数据压栈,并将浏览器地址栏的url替换成传入的url且不刷新页面。

    这两个 API 都接收三个参数,分别是:

    • 状态对象(state object) — 一个JavaScript对象,与用pushState()方法创建的新历史记录条目关联。无论何时用户导航到新创建的状态,popstate事件都会被触发,并且事件对象的state属性都包含历史记录条目的状态对象的拷贝。
    • 标题(title) — FireFox浏览器目前会忽略该参数,虽然以后可能会用上。考虑到未来可能会对该方法进行修改,传一个空字符串会比较安全。或者,你也可以传入一个简短的标题,标明将要进入的状态。
    • 地址(URL) — 新的历史记录条目的地址。浏览器不会在调用pushState()方法后加载该地址,但之后,可能会试图加载,例如用户重启浏览器。新的URL不一定是绝对路径;如果是相对路径,它将以当前URL为基准;传入的URL与当前URL应该是同源的,否则,pushState()会抛出异常。该参数是可选的;不指定的话则为文档当前URL。
      相同之处是两个 API 都会操作浏览器的历史记录,而不会引起页面的刷新。

    不同之处在于,pushState会增加一条新的历史记录,而replaceState则会替换当前的历史记录。

    https://www.baidu.com/为例:
    控制台输入

    window.history.pushState(null, null, "https://www.baidu.com/?name=orange");
    

    于是我们的url变成了

    url

    并且页面并没有刷新,只是url栏发生了变化。

    注意:这里的 url 不支持跨域,当我们把 www.baidu.com 换成 baidu.com 时就会报错。

    到此我们在不改变页面的前提下实现了url的变化。


    那么如何捕捉url的变化进行页面的替换呢?

    对于hash方式的前端路由,通常可以监听 hashchange 事件,在事件回调中处理相应的页面视图展示等逻辑。

     <script>
            function change() {
                alert("ok!");
            }
        </script>
    </head>
    <body onhashchange="change()">
    </body>
    

    在浏览器输入location.hash = "123",即弹出“ok!”

    此外,html5提供的 popstate 事件也会在url的hash发生改变时触发。也就是说如果可以忽略低版本浏览器,我们使用hash方式路由时也可以采用监听这个事件进行回调处理。

    那么,如果是采用history API的形式呢?根据MDN的描述:

    调用 history.pushState() 或者 history.replaceState() 不会触发 popstate 事件。popstate 事件只会在浏览器某些行为下触发, 比如点击后退按钮(或者在JavaScript中调用 history.back() 方法)。

    这也就是说,我们在使用history API改变浏览器的url时,仍需要额外的步骤去触发 popstate 事件,例如调用 history.back() 会 history.forward() 等方法。

    window.onpopstate = function(event) {
      alert("location: " + document.location + ", state: " + JSON.stringify(event.state));
    };
    history.pushState({page: 1}, "title 1", "?page=1");
    history.pushState({page: 2}, "title 2", "?page=2");
    history.replaceState({page: 3}, "title 3", "?page=3");
    history.back(); // alerts "location: http://example.com/example.html?page=1, state: {"page":1}"
    history.back(); // alerts "location: http://example.com/example.html, state: null
    history.go(2);  // alerts "location: http://example.com/example.html?page=3, state: {"page":3}
    

    不存在纯前端路由

    我们此前所描述的前端路由,建立在已经打开了一个初始页面基础之上,然后在这个页面之内进行页面替换。然而,我们如何进入这个初始页面?仅靠前端路由肯定是力所不及。我们至少要向后端发送一次http请求,接收所需要加载的页面不是吗?

    所以,我们并不能抛弃后端路由部分。这也意味着,我们需要和后端确认各自的分工,哪些url归前端解析,哪些归后台解析。

    相关文章

      网友评论

        本文标题:说一说不依赖服务器的前端路由

        本文链接:https://www.haomeiwen.com/subject/zbtddxtx.html