zoukankan      html  css  js  c++  java
  • 实现前端路由

         在单页应用上,前端路由并不陌生。单页应用是指在浏览器中运行的应用,在使用期间页面不会重新加载。 
          基本原理:以 hash 形式(也可以使用 History API 来处理)为例,当 url 的 hash 发生改变时,触发 hashchange 注册的回调,回调中去进行不同的操作,进行不同的内容的展示。 
          基于hash的前端路由优点是:能兼容低版本的浏览器。 
    history 是 HTML5 才有的新 API,可以用来操作浏览器的 session history (会话历史)。 
          从性能和用户体验的层面来比较的话,后端路由每次访问一个新页面的时候都要向服务器发送请求,然后服务器再响应请求,这个过程肯定会有延迟。而前端路由在访问一个新页面的时候仅仅是变换了一下路径而已,没有了网络延迟,对于用户体验来说会有相当大的提升。 

          SPA的核心即是前端路由。何为路由呢?说的通俗点就是网址,比如https://www.talkingcoder.com/article/6333760306895988699;专业点就是每次GET或者POST等请求,在服务端有一个专门的正则配置列表,然后匹配到具体的一条路径后,分发到不同的Controller,然后进行各种操作后,最终将html或数据返回给前端,这就完成了一次IO。当然,目前绝大多数的网站都是这种后端路由,也就是多页面的,这样的好处有很多,比如页面可以在服务端渲染好直接返回给浏览器,不用等待前端加载任何js和css就可以直接显示网页内容,再比如对SEO的友好等。那SPA的缺点也是很明显的,就是模板是由后端来维护或改写。前端开发者需要安装整套的后端服务,必要还得学习像PHP或Java这些非前端语言来改写html结构,所以html和数据、逻辑混为一谈,维护起来即臃肿也麻烦。然后就有了前后端分离的开发模式,后端只提供API来返回数据,前端通过Ajax获取到数据后,再用一定的方式渲染到页面里,这么做的优点就是前后端做的事情分的很清楚,后端专注在数据上,前端专注在交互和可视化上,从此前后搭配,干活不累,如果今后再开发移动App,那就正好能使用一套API了,当然缺点也很明显,就是首屏渲染需要时间来加载css和js。这种开发模式被很多公司认同,也出现了很多前端技术栈,比如以jQuery+artTemplate+Seajs(requirejs)+gulp为主的开发模式所谓是万金油了。在Node.js出现后,这种现象有了改善,就是所谓的大前端,得益于Node.js和JavaScript的语言特性,html模板可以完全由前端来控制,同步或异步渲染完全由前端自由决定,并且由前端维护一套模板,这就是为什么在服务端使用artTemplate、React以及即将推出的Vue2.0原因了。那说了这么多,到底怎样算是SPA呢,其实就是在前后端分离的基础上,加一层前端路由。

         前端路由,即由前端来维护一个路由规则。实现有两种,一种是利用url的hash,就是常说的锚点(#),JS通过hashChange事件来监听url的改变,IE7及以下需要用轮询;另一种就是HTML5的History模式,它使url看起来像普通网站那样,以"/"分割,没有#,但页面并没有跳转,不过使用这种模式需要服务端支持,服务端在接收到所有的请求后,都指向同一个html文件,不然会出现404。所以,SPA只有一个html,整个网站所有的内容都在这一个html里,通过js来处理。

         前端路由的优点有很多,比如页面持久性,像大部分音乐网站,你都可以在播放歌曲的同时,跳转到别的页面而音乐没有中断,再比如前后端彻底分离。前端路由的框架,通用的有Director,更多还是结合具体框架来用,比如Angular的ngRouter,React的ReactRouter,以及我们后面用到的Vue的vue-router。这也带来了新的开发模式:MVC和MVVM。如今前端也可以MVC了,这也是为什么那么多搞Java的钟爱于Angular。

         开发一个前端路由,主要考虑到页面的可插拔、页面的生命周期、内存管理等。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    (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;
        }
    })();

      每次hash的变化我们还可以通过onhashchange事件【核心+精髓】来监听,然后做出相应的处理。。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    <!DOCTYPE html>
    <html>
     
        <head>
            <meta charset="utf8" />
            <script type="text/javascript" src="./router.js"></script>
            <style type="text/css">
            </style>
        </head>
     
        <body>
            <a href="#!index">go to index</a><br />
            <a href="#!search/SB/shi/ni">go to search</a>
        </body>
     
        <script type="text/javascript">
            window.onload = function() {
                var router = new Router();
                router.add('index', function() {
                    alert('current page: index');
                });
     
                router.add('search', function(wd, sortType, sortBy) {
                    alert('current page: search' + ' wd: ' + wd + ' sortType: ' + sortType + ' sortBy: ' + sortBy);
                });
                router.setIndex('index');
                router.start();
            };
        </script>
     
    </html>
  • 相关阅读:
    js编码中常用的知识点
    oracle函数的使用
    oracle 临时表的使用
    oracle11G归档日志管理
    oracle中 高水位线详解
    oracle并行模式(Parallel)
    oracle常用函数详解(详细)
    oracle系统表的查询
    15000 字的 SQL 语句大全
    oracle_单引号问题和execute immediate 赋值问题
  • 原文地址:https://www.cnblogs.com/ckAng/p/10234596.html
Copyright © 2011-2022 走看看