前端路由的不同方法实现

在讲前端路由之前,先说下后端路由,以及为什么出现了前端路由。
后端路由: 浏览器在地址栏中切换不同的url时,每次都向后台服务器发出请求,服务器响应请求,在后台拼接html文件传给前端显示,java web中的jsp就是如此实现的。常用的后台MVC模式的基本路由处理流程:浏览器输入一个url请求,从中找到Controller和Action的值,将请求传递给Controller处理,Controller获取Model数据对象,并且将Model传递给View,最后View呈现界面。
例如输入一个url:localhost/home/index
其中localhost是域名,对应结构{controller}/{action}/{id}

  • 优点:分担了前端的压力,html和数据的拼接都是由服务器完成。
  • 缺点:当项目十分庞大时,加大了服务器端的压力,同时在浏览器端不能输入制定的url路径进行指定模块的访问。另外一个就是如果当前网速过慢,那将会延迟页面的加载,对用户体验不是很友好。

    前端路由: 随着(SPA)单页应用的不断普及,前后端开发分离,目前项目基本都使用前端路由,在项目使用期间页面不会重新加载。

  • 优点:1、用户体验好,和后台网速没有关系,不需要每次都从服务器全部获取,界面展现快。2、可以再浏览器中输入指定想要访问的url路径地址。3.实现了前后端的分离,方便开发。有很多框架都带有路由功能模块。

  • 缺点:1、对SEO不是很友好2、在浏览器前进和后退时候重新发送请求,没有合理缓存数据。3,初始加载时候由于加载所有模块渲染,会慢一点。

    前端路由目前主要有两种方法:

  • 1、利用url的hash,就是常用的锚点(#)操作,类似页面中点击某小图标,返回页面顶部,JS通过hashChange事件来监听url的改变,IE7及以下需要轮询进行实现。一般常用框架的路由机制都是用的这种方法,例如Angualrjs自带的ngRoute和二次开发模块ui-router,react的react-route,vue-route…
  • 2、利用HTML5的History模式,使url看起来类似普通网站,以”/”分割,没有”#”,但页面并没有跳转,不过使用这种模式需要服务器端的支持,服务器在接收到所有的请求后,都指向同一个html文件,通过historyAPI,监听popState事件,用pushState和replaceState来实现。具体API参考MDN文档https://developer.mozilla.org…
    由于使用hash方法能够兼容低版本的IE浏览器,简单的的自己搭建前端路由。

方法一:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>前端路由实现</title>   
</head>
<body>
<ul>
    <li><a href="#/"></a></li>
    <li><a href="#/home">主页</a></li>
    <li><a href="#/about">详情页</a></li>
</ul>
<script type="text/javascript" src="router.js"></script>
<script type="text/javascript">
var content = document.querySelector('body');
Router.route('/', function() {
    console.log("这是主页");
});
Router.route('/home', function() {
    console.log("这是主页");
});
Router.route('/about', function() {
    console.log("这是详情页");
});
</script>
</body>
</html>

router.js

//构造函数
function Router() {
    this.routes = {};
    this.currentUrl = '';
}
//route 存储路由更新时的回调到回调数组routes中,回调函数将负责对页面的更新
Router.prototype.route = function(path, callback) {
    this.routes[path] = callback || function(){};//给不同的hash设置不同的回调函数
};
//refresh 执行当前url对应的回调函数,更新页面
Router.prototype.refresh = function() {
    console.log(location.hash.slice(1));//获取到相应的hash值
    this.currentUrl = location.hash.slice(1) || '/';//如果存在hash值则获取到,否则设置hash值为/
    // console.log(this.currentUrl);
    this.routes[this.currentUrl]();//根据当前的hash值来调用相对应的回调函数
};
//init 监听浏览器url hash更新事件
Router.prototype.init = function() {
    window.addEventListener('load', this.refresh.bind(this), false);
    window.addEventListener('hashchange', this.refresh.bind(this), false);
}
//给window对象挂载属性
window.Router = new Router();
window.Router.init();

方法二:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf8" />
        <script type="text/javascript" src="./router.js"></script>
        <style type="text/css">
        </style>
    </head>
    <body>
        <li><a href="#/"></a></li>
        <li><a href="#/home">主页</a></li>
        <li><a href="#/about">详情页</a></li>
    </body>
    <script type="text/javascript">
        window.onload = function() {
            var router = new Router();
            router.add('home', function() {
                console.log('这是主页');
            }); 
            router.add('about', function() {
                console.log('这是详情页');
            });
            router.setIndex('home');
            router.start();
        };
    </script>
</html>

router.js

(function() {
    window.Router = function() {
        var self = this;
        self.hashList = {}; /* 路由表 */
        self.index = null;
        self.key = '/';
        window.onhashchange = function() {
            self.reload();
        };
    }; 
    /**
     * 添加路由,如果路由已经存在则会覆盖
     * @param addr: 地址
     * @param callback: 回调函数,调用回调函数的时候同时也会传入相应参数
     */
    Router.prototype.add = function(addr, callback) {
        var self = this;
        self.hashList[addr] = callback;
    };
    /**
     * 删除路由
     * @param addr: 地址
     */
    Router.prototype.remove = function(addr) {
        var self = this;
        delete self.hashList[addr];
    };
    /**
     * 设置主页地址
     * @param index: 主页地址
     */
    Router.prototype.setIndex = function(index) {
        var self = this;
        self.index = index;
    };
    /**
     * 跳转到指定地址
     * @param addr: 地址值
     */
    Router.prototype.go = function(addr) {
        var self = this;
        window.location.hash = '#' + self.key + addr;
    }; 
    /**
     * 重载页面
     */
    Router.prototype.reload = function() {
        var self = this;
        var hash = window.location.hash.replace('#' + self.key, '');
        var addr = hash.split('/')[0];
        var cb = getCb(addr, self.hashList);
        if(cb != false) {
            var arr = hash.split('/');
            arr.shift();
            cb.apply(self, arr);
        } else {
            self.index && self.go(self.index);
        }
    };
    /**
     * 开始路由,实际上只是为了当直接访问路由路由地址的时候能够及时调用回调
     */
    Router.prototype.start = function() {
        var self = this;
        self.reload();
    }
    /**
     * 获取callback
     * @return false or callback
     */
    function getCb(addr, hashList) {
        for(var key in hashList) {
            if(key == addr) {
                return hashList[key]
            }
        }
        return false;
    }
})();

模拟hashchange 在低版本 IE 需要通过轮询监听 url 变化来实现:

(function(window) {
  // 如果浏览器不支持原生实现的事件,则开始模拟,否则退出。
  if ( "onhashchange" in window.document.body ) { return; }
  var location = window.location,
  oldURL = location.href,
  oldHash = location.hash;
  // 每隔100ms检查hash是否发生变化
  setInterval(function() {
    var newURL = location.href,
    newHash = location.hash;
    // hash发生变化且全局注册有onhashchange方法(这个名字是为了和模拟的事件名保持统一);
    if ( newHash != oldHash && typeof window.onhashchange === "function"  ) {
      // 执行方法
      window.onhashchange({
        type: "hashchange",
        oldURL: oldURL,
        newURL: newURL
      });
      oldURL = newURL;
      oldHash = newHash;
    }
  }, 100);
})(window);

主要就是监听hash的变更,然后在里面根据配置,用ajax去读对应的界面片段,然后append到主容器中就可以了。市面上的选择比较多的是:director.js,path.js,Backbone.Router,leeluolee/stateman · GitHub

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值