了解路由hash和history

625 阅读3分钟

路由其实就是在网址url产生变化的时候展示相应的代码块,但是我们要实现路由的效果必须要解决下面的问题,首先点击a标签虽然会使url发生变化,但是url发生变换后页面会进行刷新,如果进行刷新的话会严重影响用户体验,例如该页面需要重新从服务器中进行加载等... 还有就是在url发生变化时我们要知道并且在页面上展示相应的代码块

hash

首先改变url,我们只需要使用<a href="/home">首页</a>,就可以了,然后我们要使url改变后页面不会刷新,首先我们就要知道哈希部分的改变不会引起页面刷新,而在url#后面的部分会被算作哈希部分,所以我们要将a标签改为<a href="#/home">首页</a>,这样就解决了url改变后页面刷新的问题,接下来就是我们要对url的哈希部分进行监听,然后展示相应的代码块,我们可以使用windows上自带的方法

window.addEventListener("hashchange", function() {
  console.log("Hash changed to:", location.hash);
});

这段代码中addEventListenerwindow自带的监听方法,这里是监听"hashchange"事件,即哈希值改变的事件,监听成功后执行回调函数,location.hash是我们在回调函数中可以获得的哈希值,然后我们要在提前学好的路由中去找我们所写的的path代表的哈希部分,找到则将该路由部分的代码块展示在页面中

下面我来写一个实例

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <ul>
        <li>
            <a href="#/home">首页</a>
        </li>
        <li>
            <a href="#/about">关于</a>
        </li>
    </ul>
    <div id="app"></div>
    <script>
        const routes = [
            {
                path: '/home',
                component: () => {
                    return '<h2>首页页面</h2>'
                }
            },
            {
                path: '/about',
                component: () => {
                    return '<h3>about首页</h3>'
                }
            }
        ]
        window.addEventListener('DOMContentLoaded', () => {
            routerView(location.hash)
        })

        window.addEventListener('hashchange', () => {
            routerView(location.hash)
        })
        function routerView(localHash) {
            //去routes数组中,查找localHash值在哪一项
            //如果找到了,就将这一项中的component执行结果放进 qpp 容器中
            console.log(localHash);
            
            const index = routes.findIndex((item) => {
                return localHash === '#' + item.path
            })
            app.innerHTML = routes[index].component()
        }
    </script>
</body>

</html>

下面这段代码是表示在html文档加载完后执行,这是为了防止用户手动点击刷新url不会发生变化,但是相应的代码块没有展示出来,所以为了在刷新后url对应的代码块也展示出来所以我们要监听文档结束并重新展示相应的代码块

window.addEventListener('DOMContentLoaded', () => { routerView(location.hash) })

history

上面我们使用了哈希部分改变不会使页面刷新的特性,并对哈希值进行监听,展示相应的代码块完成路由的效果,那这个history有什么特性使得我们可以达到路由的效果呢,这个history内的方法可以使url改变,并且不会使页面刷新,也不会展示相应的代码块,但是a标签已经包含了改变url的功能呀,为什么还要用history呢,因为a标签还会使页面刷新,所以我们要阻止a标签的默认行为,使用preventDefault(),然后我们要拿到在a标签在点击后的href属性,使用history.pushState()href属性添加到url中去,然后将我们提前创建好的路由对象中的path属性去和url的路径进行比较,使用location.pathname来获得当前url的路径。最后展示相应的代码块就可以了,下面来我写一个实例

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <ul>
        <li>
            <a href="/home">首页</a>
        </li>
        <li>
            <a href="/about">关于</a>
        </li>
    </ul>
    <div id="app"></div>

    <script>
        const routes = [
            {
                path: '/home',
                component: () => {
                    return '<h2>首页页面</h2>'
                }
            },
            {
                path: '/about',
                component: () => {
                    return '<h3>about首页</h3>'
                }
            }
        ]
    window.addEventListener('popstate', function(){
        routerView()
        })
    
        let linkList = document.querySelectorAll('a')
        console.log(linkList);
        
    linkList.forEach(link =>{
        link.addEventListener('click',function(e){
            //让a标签不跳转
            e.preventDefault() //阻止默认行为
            // 让url地址发生变化
            history.pushState(null,'',this.getAttribute('href'))
            routerView()
        })
    })
    const app = document.getElementById('app')
    function routerView() {
        const index = routes.findIndex((item) => {
            return location.pathname ===  item.path
        })
        app.innerHTML = routes[index].component()
    }
    
    </script>
</body>

</html>

下面这段代码是在浏览器发生前进后退等事件时调用routerView()函数

window.addEventListener('popstate', function(){ routerView() })

小结

其实要实现路由的功能只需要解决这几点就可以了

  1. 浏览器不能刷新
  2. 监听url的变化
  3. url变化时要展示相应的代码块

掌握这几点再利用hashhistory的特性就可以熟悉掌握路由的配置了