前端路由hash模式和history模式实现原理

8 篇文章 0 订阅
相信大家一开始接触框架的时候都有疑问为什么我们的路由变化了却没有页面跳转,后来我看了各种资料,也了解了hash值和history的两种实现方法。于是实现前端路由也不再是难事。
话不多说,翠花,上代码~~~
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>原生实现hash和browser两种路由模式</title>
</head>
<body>
    <div class="router_box">
        <a href="/home" class="router" replace="true">主页</a>
        <a href="/news" class="router">新闻</a>
        <a href="/team" class="router">团队</a>
        <a href="/about" class="router">关于</a>
        <a href="/abcd" class="router">随便什么</a>
    </div>
    <div id="router-view"></div>
    <script>
        function Router(params){
            // 记录routes配置
            this.routes = params.routes || [];
            // 记录路由模式
            this.mode = params.mode || 'hash';
            console.log('this.mode', this.mode);
            // 初始化
            this.init = function(){
                // 绑定路由响应事件
                var that = this;
                document.querySelectorAll(".router").forEach((item,index)=>{
                    item.addEventListener("click",function(e){
                        // 阻止a标签的默认行为
                        if ( e && e.preventDefault ){
                            e.preventDefault(); 
                        }else{
                            window.event.returnValue = false;  
                        } 
                        
                        if (that.mode == 'hash'){
                            // 判断是replace方法还是push方法
                            if (this.getAttribute("replace")){
                                var i = window.location.href.indexOf('#')
                                // 通过replace方法直接替换url
                                window.location.replace(
                                    window.location.href.slice(0, i >= 0 ? i : 0) + '#' + this.getAttribute("href")
                                )
                            }else{
                                // 通过赋值追加
                                window.location.hash = this.getAttribute("href");
                            }
                        }else{
                            if (this.getAttribute("replace")){
                                window.history.replaceState({}, '', window.location.origin+this.getAttribute("href"))
                                that.routerChange();

                            }else{
                                window.history.pushState({}, '', window.location.origin+this.getAttribute("href"))
                                that.routerChange();

                            }
                        }
                        
                    }, false);
                });
                // 监听路由改变
                if (this.mode == 'hash'){//hash模式时监听hashchange
                    window.addEventListener("hashchange",()=>{
                        this.routerChange();
                    });
                }else{//history模式时监听popstate事件
                    window.addEventListener('popstate', e => {
                        console.log(123);
                        this.routerChange();
                    })
                }
                this.routerChange();
            },
            // 路由改变监听事件
            this.routerChange = function(){
                if (this.mode == 'hash'){
                    let nowHash=window.location.hash;
                    let index=this.routes.findIndex((item,index)=>{
                        return nowHash == ('#'+item.path);
                    });
                    if(index>=0){
                        document.querySelector("#router-view").innerHTML=this.routes[index].component;
                    }else {
                        let defaultIndex=this.routes.findIndex((item,index)=>{
                            return item.path=='*';
                        });
                        if(defaultIndex>=0){
                            const i = window.location.href.indexOf('#')
                            window.location.replace(
                                window.location.href.slice(0, i >= 0 ? i : 0) + '#' + this.routes[defaultIndex].redirect
                            )
                        }
                    }
                }else{
                    let path = window.location.href.replace(window.location.origin, '');
                    let index=this.routes.findIndex((item,index)=>{
                        console.log('path...', path, 'item.path...', item.path);
                        return path == item.path;
                    });
                    if(index>=0){
                        document.querySelector("#router-view").innerHTML=this.routes[index].component;
                    }else {
                        let defaultIndex=this.routes.findIndex((item,index)=>{
                            return item.path=='*';
                        });
                        if(defaultIndex>=0){
                            console.log(window.location.origin+this.routes[defaultIndex].redirect)
                            window.history.pushState({}, '', window.location.origin+this.routes[defaultIndex].redirect)
                            this.routerChange();
                            
                        }
                    }
                }
            }
            // 调用初始化
            this.init();
        }
        new Router({
            mode: 'hash',
            routes:[
                { path: '/home', component: '<h1>主页</h1><h4>新一代前端工程师:我们啥都会</h4>' },
                { path: '/news', component: '<h1>新闻</h1><h4>今天2019-6-11</h4>' },
                { path: '/team', component: '<h1>团队</h1><h4>WEB前端工程师</h4>' },
                { path: '/about', component: '<h1>关于</h1><h4>我们都要加油</h4>' },
                { path:'*', redirect:'/home'}
            ]
        });
    </script>
</body>
</html>
分析

前端路由中我们主要是利用history.replaceState() history.pushState或者改变hash值不会使页面重新加载,然后监听路由的变化来做到触发对应时间加载对应资源来重新绘制页面。
这里比较重要的点是,监听hash模式用的是hashchange,history模式用的是popstate

  • 5
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值