0
点赞
收藏
分享

微信扫一扫

vue 两种路由模式具体实现

DT_M 2022-08-31 阅读 80

背景

  • 单页面
    众多周知,我们前端在开发的时候,一般将一个index.html 页面放在后端。这个 index.html即我们访问的单页面。我们在首次访问时直接访问后端部署的index.html路径即可。在请求到这个index.html页面后,后续切换页面展示内容不需要再次请求,这正是由于路由的作用。
  • 路由
    通过某种方式,监听用户动作行为,进而展示不同的内容
  • 两种路由
    众所周知,前端现在流行两种路由模式,history和hash模式

hash模式

  • 原理
    不同路由对应的hash值不一样,在改变hash值时并不会重新发送请求。

  • 实现原理
    根据浏览器提供的hashchange方法,监听不同hashchange进而引入不同的内容显示

  • 具体实现

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

<head>
    <meta charset="UTF-8">
    </meta>
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    </meta>
    <meta content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no,viewport-fit=cover"
        name="viewport">
    </meta>
    <title>hash模式</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        html,
        body {
            width: 100%;
            height: 100%;
        }

        .tag {
            width: 100%;
            display: flex;
            justify-content: space-around;
        }

        .app {
            width: 100%;
            font-size: 15px;
        }
    </style>
</head>

<body>
    <div class="tag">
        <a href="#/">首页</a>
        <a href="#/shop">商品</a>
        <a href="#/mine">我的</a>
    </div>
    <div id="app" class="app"></div>
</body>

<script>
    class VueRouter {
        constructor(routes = []) {
            this.routes = routes;
            this.currHash = '';
            this.refresh = this.refresh.bind(this);
            window.addEventListener('load', this.refresh, false);
            window.addEventListener('hashchange', this.refresh, false);// 重点监听hashchange方法
        }
        
        // 获得hash值
        getHashValue(url) {
            return url.indexOf('#') >= 0 ? url.slice(url.indexOf('#') + 1) : '/';
        }

        // 刷新
        refresh(event){
            let newHash = '',oldHash = '';
            if(event.newURL){
                oldHash =  this.getHashValue(event.oldURL || '');
                newHash = this.getHashValue(event.newURL||''); // 页面之间跳转使用
            }
            else {
                newHash = this.getHashValue(window.location.hash); // 初次加载时跳转
            }
            this.currHash = newHash;
            this.matchComponent();
        }
       
        // 插入html
        matchComponent(){
            let curRoute = this.routes.find(route=>route.path===this.currHash) // 找到当前路由配置的route
            if(!curRoute){
                curRoute = this.routes.find(route=>route.path === '/') // 找不到取默认第一个
            }
            
            const {component} = curRoute;
            console.log(component);
            document.querySelector('#app').innerHTML = component; // 渲染html
        }
        
    }

    const router = new VueRouter([
        {
            path:'/',
            name:"home",
            component:'<div>首页</div>'
        },  {
            path:'/shop',
            name:"shop",
            component:'<div>商品</div>'
        },
         {
            path:'/mine',
            name:"mine",
            component:'<div>我的</div>'
        }
    ])
</script>

</html>
  • 特点
    1 只需在前端操作 无需后端辅助
    2 使用hashchange监听,渲染不同页面
    3 改变路由在url中#后面

history模式

  • 原理
    通过浏览器提供的 pushstate和replacestate。pushstate增加浏览器的会话历史栈,replacestate替换当前的会话历史,故不会重新请求url。 但是因为popstate不能监控到pushstate和replacestate,所以我们需要自定义监控事件,合适的时机抛出
  • 具体实现
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    </meta>
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    </meta>
    <meta content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no,viewport-fit=cover"
        name="viewport">
    </meta>
    <title>history模式</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        html,
        body {
            width: 100%;
            height: 100%;
        }

        .tag {
            width: 100%;
            display: flex;
            justify-content: space-around;
        }

        .app {
            width: 100%;
            font-size: 15px;
        }
    </style>
</head>

<body>
    <div class="tag">
        <div id="button1">首页</div>
        <div id="button2">商品</div>
        <div id="button3">我的</div>
    </div>
    <div id="app" class="app"></div>
</body>

<script>
   
   // 改写事件,合适时机抛出
    let _wr =function(type){
        let origin = history[type] // 获取调用的方法;
        return function(){
            console.log(origin)
            let res = origin.apply(this,arguments); // argument 即进行的路由
            let e = new Event(type) ; // 创建自定义抛出事件
            e.arguments = arguments;
            window.dispatchEvent(e) ;// 抛出 可以监听
            return res;
        }
    }
    history.pushState = _wr('pushState');
    history.replaceState = _wr("replaceState");// 改写方法

    const btn1 = document.querySelector('#button1');
     const btn2 = document.querySelector('#button2');
      const btn3 = document.querySelector('#button3');
     btn1.addEventListener('click',()=>{
        history.pushState({ state:1 },null,'./home') // 三个参数 状态 标题(大都忽略)URL
     })
       btn2.addEventListener('click',()=>{
        history.pushState({state:2},null,'./shop')
     })
       btn3.addEventListener('click',()=>{
        history.pushState({state:3},null,'./mine')
     })

     window.addEventListener('pushState',(e)=>{
         // 根据 e中参数 查找到
         console.log(e.arguments)
        //  router.matchComponent(e.) // 调用获取路由然后展示
     })

    class VueRouter {
        constructor(routes = []) {
            this.routes = routes;
        }
        
    matchComponent(){
            let curRoute = this.routes.find(route=>route.path===this.currHash) // 找到当前路由配置的route
            if(!curRoute){
                curRoute = this.routes.find(route=>route.path === '/') // 找不到取默认第一个
            }
            
            const {component} = curRoute;
            console.log(component);
            document.querySelector('#app').innerHTML = component; // 渲染html
        }
    }

    const router = new VueRouter([
        {
            path:'/',
            name:"home",
            component:'<div>首页</div>'
        },  {
            path:'/shop',
            name:"shop",
            component:'<div>商品</div>'
        },
         {
            path:'/mine',
            name:"mine",
            component:'<div>我的</div>'
        }
    ])
</script>

</html>
  • 特点
    1 通过pushstate来进行路由切换,无需刷新页面
    2 路径URL比较清晰
    3 切换路由后** 刷新会报错** ,需要后端帮忙Nginx重新请求到index.html

参考文章

1 .[https://juejin.cn/post/7127143415879303204][https://juejin.cn/post/7127143415879303204]

举报

相关推荐

0 条评论