前端路由?如何手动实现前端路由

我报名参加金石计划一期挑战——瓜分10万奖池,这是我的第三篇文章,点击查看活动详情

前端最开始是没有路由这个概念的,因为最早的时候,前端负责切图的时候,一个html文件路径对应着一个页面,是没有路由这个概念的,只有页面和路径的概念的。而随着前端的发展,前端也不再只是作为一个单单的切图仔的角色,路由这个概念也随之引入。

什么是前端路由?

说到什么是前端路由,咱们先来举个栗子吧。

这里,我们在掘金首页,路径为:juejin.cn/recommended

image.png

然后我们点击一下沸点:

路径变为:juejin.cn/pins

image.png

这里我们可以看到的是,路径只有最后最后面一部分的路径发生了改变,前面的路径并没有发生改变。

这说明什么?这其实是个单页页面,只存在一个页面,点击进行跳转只是通过改变路径,而渲染出不同的页面效果,但是值得一提的是,页面并没有进行刷新,这里是有一个过程量的

即你在首页页面点击沸点之前和点击沸点之后,你可以看到那个页面刷新按钮是没有进行刷新的。

L{84)19$6KR05A7Z7BPMWJ4.png

总结:前端路由就是描述url 和 页面ui 之间的映射关系,单向映射。

扫描二维码关注公众号,回复: 14514476 查看本文章

实现路由应该做到什么?

1.如何改变url却不引起页面的刷新

2.如何检测url发生了变化

实现前端路由的方式

hash

hash又被叫为哈希,须知的是改变浏览器url的hash值部分,页面是不会刷新的。

这里,我们写了两个a标签,路径分别为/home/about,那么这点击这两个a标签超链接,我们的页面就会发生跳转,进入下一个页面,即多页应用。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <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>

    <!-- 渲染对应的UI -->
    <div id="routerView"></div>
</body>
</html>
复制代码

那么,如何实现hash路由呢?

首先,我们只要把a标签的路径改为#/home#/about,hash路径都要加上一个#前缀,浏览器会自动识别这是hash路径,从而达到路径发生改变,但页面并没有进行刷新跳转,仍旧处于原本这个页面。

<body>
    <ul>
        <li>
            <a href="#/home">首页</a>
        </li>
        <li>
            <a href="#/about">关于</a>
        </li>
    </ul>
</body>
复制代码

可浏览器识别了路径的hash值发生了改变,页面也并没有什么其它的东西渲染出来啊?这就是我们需要解决的第二个问题了,怎样检测监听页面url的改变,我们只需要检测到页面url的改变,且获取改变的那一段页面url,来判断那一段url应该在页面上渲染什么。

那么,怎么检测页面url发生改变呢?

window.addEventListener('hashchange',onHashChange)
复制代码

JS自带一个有关于window事件的监听,第一个参数为hashchange,即监听页面url的hash值改变,第二个参数为一个函数,这里我们为了好看一点,这里放上函数名onHashChange

只要页面的url里hash值部分发生改变,那么就会调用onHashChange函数。

再通过location.hash来获取页面改变的hash值部分在函数里面来决定应该渲染哪一部分页面。

完整代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <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>

    <!-- 渲染对应的UI -->
    <div id="routerView"></div>

    <script>
        let routerView = document.getElementById('routerView')
        window.addEventListener('hashchange',onHashChange)

        //控制渲染对应的ui
        function onHashChange(){
            switch(location.hash){
                case '#/home':routerView.innerHTML='首页'
                braek;
                case '#/about':routerView.innerHTML='关于'
                break;
                default:return
            }
        }
    </script>
</body>
</html>
复制代码

效果如图:

~N1}ADKSZTBN1Q28O8%`R`0.png 73M13IR(_$9FWRE2}NTZH8B.png SR))O@1H[YS~O0IUEKYG6N7.png

hash实现路由非常简便,但是有一个小弊端,就是路径不美观,每一段路径都会加一个#号,而路径我们一般都是/去分割,多加一个#不太美观,所以我们通常用history方法实现路由用的更多。

history

history是HTML5提供的一个对象方法。

而我们要实现history路由之前,我们应该知道这么三种方法:

  1. pushState //增加url,且不会引起页面变化
  2. replaceState //修改url 并且不会引起页面刷新的
  3. popState //监听url变化

在用history方法之前,我们需要先监听a标签的点击事件,然后阻止a标签自带的跳转,这里我们使用preventDefault()方法。

a.getAttribute('href')获取a标签里的href路径,用作于history的history.pushState(null,'',a.getAttribute('href'))里,添加改变路径。

再调用PoPState函数决定渲染哪一部分的函数

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <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>

    <!-- 渲染对应的UI -->
    <div id="routerView"></div>
    <script>
        let routerView = document.getElementById('routerView')

        window.addEventListener('DOMContentLoaded',onLoad)    //页面第一次加载就进行默认选中渲染内容
        // window.addEventListener('popstate',PoPState)          //浏览器的前进后退能匹配
        function onLoad(){
            PoPState()
            let links = document.querySelectorAll('li a[href]')
            links.forEach(a=>{
                a.addEventListener('click',(e)=>{
                    e.preventDefault();      //阻止a标签的href标签
                    
                    history.pushState(null,'',a.getAttribute('href'))
                    PoPState()
                })
            })
        }
        onLoad()
        function PoPState(){
            switch(location.pathname){
                case '/home':
                    routerView.innerHTML = '<h2>home page</h2>'
                    return
                case '/about':
                    routerView.innerHTML = '<h2>about page</h2>'
                    return
                default:
                    return
            }
        }
    </script>
</body>
</html>
复制代码

效果如下:

image.png image.png image.png

总体来说,都是通过改变页面url但不刷新页面,然后判断路径来选择不同的组件来渲染页面实现路由效果。

猜你喜欢

转载自juejin.im/post/7143064688661069854