乐趣区

关于前端:VueRouter原理实现八1

写在结尾

左思右想还是决定再加一章,这章次要介绍路由的原理实现,并且会应用代码模仿 VueRouter 的原理。我学习前端的感觉是,框架有很多,会用就能够。但设计的思维却值得咱们去钻研,因为这才是框架的灵魂,以及真正的智慧所在。其实在应用框架的时候咱们不难发现,有些命令或者办法咱们用的多了甚至能猜出它的设计思维以及实现原理。所以纯熟应用一个框架或者并不难,但如果不能懂得它设计的初衷以及其中的奥秘,就总是会感觉短少一些什么。废话少说,进入正题。

1. 模式

先看看这个:https://blog.csdn.net/fifteen…

援用其中的一段话,对于 hash 和 history 的区别( 划重点,要考!):

hash 模式 url 外面永远带着 #号,咱们在开发当中默认应用这个模式。那么什么时候要用 history 模式呢?如果用户思考 url 的标准那么就须要应用 history 模式,因为 history 模式没有#号,是个失常的 url 适宜推广宣传。当然其性能也有区别,比方咱们在开发 app 的时候有分享页面,那么这个分享进来的页面就是用 vue 或是 react 做的,咱们把这个页面分享到第三方的 app 里,有的 app 外面 url 是不容许带有#号的,所以要将# 号去除那么就要应用 history 模式,然而应用 history 模式还有一个问题就是,在拜访二级页面的时候,做刷新操作,会呈现 404 谬误,那么就须要和后端人配合让他配置一下 apache 或是 nginx 的 url 重定向,重定向到你的首页路由上就 ok 啦。

VueRouter 领有两种模式,那就是咱们相熟的 hash 和 history,所以在设计时也要将这两种不同的模式都思考进来。代码如下:
hash:

<body>
    <!-- a 标签 = router-link  -->
    <a href="#/"> 首页 </a>
    <a href="#/about"> 对于 </a>
    <!-- div = router-view  -->
    <div id="view"></div>

    <script>
        const vw = document.getElementById("view")
        window.addEventListener("hashchange", () => {if (location.hash == "#/") {vw.innerHTML = "我是首页"} else if (location.hash == "#/about") {vw.innerHTML = "我是对于"}
        })
    </script>
</body>

看看成果:

那么问题来了,router-link 的 tag 属性能够扭转显示的标签。也就是说如果不是默认的 a 标签该怎么做呢?持续改良,代码如下:

<body>
    <!-- 任意标签 = router-link  -->
    <span style="color: deepskyblue;cursor:pointer;" onclick="changeHash('#/')"> 首页 </span>
    <span style="color: deepskyblue;cursor:pointer;" onclick="changeHash('#/about')"> 对于 </span>
    <!-- div = router-view  -->
    <div id="view"></div>

    <script>
        function changeHash (path) {location.hash = path}
        window.addEventListener("hashchange", () => {if (location.hash == "#/") {view.innerHTML = "我是首页"} else if (location.hash == "#/about") {view.innerHTML = "我是对于"}
        })
    </script>
</body>

看看成果:

解决方案就是咱们能够通过为任意标签增加点击事件,并在点击时传入对应的 hash 值,而后在点击事件处理函数中扭转地址栏的 hash 值。

能够看到,应用 a 标签和 div 模仿的 vueRouter,仿佛还像那么回事儿。所以 hash 模式下路由的原理也不言而喻,说白了就是:

监听 hashchange 事件,而后依据地址栏上的门路,进行 DOM 渲染。

history:

<body>
    <!-- 任意标签 = router-link  -->
    <span style="color: deepskyblue;cursor:pointer;" onclick="changeHash('/')"> 首页 </span>
    <span style="color: deepskyblue;cursor:pointer;" onclick="changeHash('/about')"> 对于 </span>
    <!-- div = router-view  -->
    <div id="view"></div>

    <script>
        function changeHash (path) {history.pushState(null, null, path)
            if (location.pathname == "/") {view.innerHTML = "首页是我"} else if (location.pathname == "/about") {view.innerHTML = "对于是我"}
        }
    </script>
</body>

看看成果:

能够看到浏览器的回退和后退并没有成果,这也是与 hash 模式不同的中央。改良:

<body>
    <!-- 任意标签 = router-link  -->
    <span style="color: deepskyblue;cursor:pointer;" onclick="changeHash('/')"> 首页 </span>
    <span style="color: deepskyblue;cursor:pointer;" onclick="changeHash('/about')"> 对于 </span>
    <!-- div = router-view  -->
    <div id="view"></div>

    <script>
        function changeHash (path) {history.pushState(null, null, path)
            if (location.pathname == "/") {view.innerHTML = "首页是我"} else if (location.pathname == "/about") {view.innerHTML = "对于是我"}
        }
        window.addEventListener("popstate", () => {if (location.pathname == "/") {view.innerHTML = "首页是我"} else if (location.pathname == "/about") {view.innerHTML = "对于是我"}
        })
    </script>
</body>

看看变动:

那么其实 history 模式下的路由原理其实也能够总结进去了:
应用 history.pushState API 来切换地址栏的门路,再通过监听 popstate 事件来操作浏览器的回退和后退按钮。

总结

代码没什么可讲的,着重说说 hash 和 history 各自的特点。

1.hash:”#” 能够了解为锚点,它的 url 会更改、浏览器能够后退和后退、但浏览器不会刷新、并且不会和服务端交换
2.history:无 ”#” 能够了解为没有锚点,它是标准的 url、是可能拜访到后盾的、须要服务端的共事进行配合

原本想着这一章把原理的内容都写完,但切实是模仿路由的内容太多了,还是放在前面一点一点写完吧。本章曾经将路由的原理带进去了,前面的内容会绝对高级的实现路由。


Keep foolish, keep hungry.

退出移动版