手写Vue-router

169 阅读1分钟

下面内容为阅读笔记,资料来源参考最后一部分。

核心原理

1. 什么是前端路由
在web前端单页应用SPA(Single Page Apllication)中,路由描述的是URL和UI之间的映射关系,这种映射是单向的,即URL变化引起UI更新(无需刷新页面)

2. 如何实现的前端路由
要实现前端路由,需要解决两个核心:

  • 如何改变URL却不引起页面刷新?
  • 如何检测URL变化?
    下面分别使用hash和history两种实现方式回答上面的两个核心问题。

hash实现
hash是URL中hash(#)及后面的那部分,常用作锚点在页面进行导航,改变URL中的hash部分不会引起页面刷新。
通过hashChange事件监听URL的变化,改变URL的方式有三种:

  • 通过浏览器前进后退改变URL
  • 通过<a>标签改变URL
  • 通过window.location改变URL

history实现
history提供了pushStatereplaceState两个方法,这两个方法改变URL的path部分不会引起页面刷新
history提供了类似hashChange事件的popstate事件,但popstate事件有些不同:

  • 通过浏览器前进后退改变URL时会出发popstate事件
  • 通过pushState/repaceState<a>标签改变URL不会出发popstate事件。
  • 可以拦截pushState/repaceState的调用和<a>标签的点击事件来检测URL变化
  • 通过js调用historybackgoforward方法触发该事件

所以监听URL变化可以实现,只是hashChange方便。

原生JS实现前端路由

hash实现

<body>
    <div>
        <a href="#/js">JS</a>
        <a href="#/vue">VUE</a>

        <!-- 根据不同路由显示不同的内容 -->
        <div id="router-view"></div>
    </div>
    <script>
        let routerView = document.getElementById('router-view');
        window.addEventListener('hashchange', () => {
            routerView.innerHTML = `这是hash- ${location.hash} 对应的UI`;
        });
        window.addEventListener('DOMContentLoaded', () => {
            if(!location.hash) {
                location.hash = '/';
            }
            else {
                routerView.innerHTML = `这是hash- ${location.hash} 对应的UI`;
            }
        })
    </script>
</body>

history实现

<body>
    <div>
        <a href="/js">JS</a>
        <a href="/vue">VUE</a>

        <!-- 根据不同路由显示不同的内容 -->
        <div id="router-view"></div>
    </div>
    <script>
        let routerView = document.getElementById('router-view');
        window.addEventListener('DOMContentLoaded', load);
        window.addEventListener('popstate', ()=>{
            routerView.innerHTML = location.pathname
        })
        function load() {
            routerView.innerHTML = ${location.pathname};
            var linkList = document.querySelectorAll('a[href]')
            linkList.forEach(el => el.addEventListener('click', function (e) {
                e.preventDefault()
                history.pushState(null, '', el.getAttribute('href'))
                routerView.innerHTML = location.pathname
            }))
        }
    </script>
</body>

参考资料

手写Vue-router核心原理,再也不怕面试官问我Vue-router原理