• 一起来单页应用吧,实现简单微博功能!(下)


    一起来单页应用吧,实现简单微博功能!(下)

    前言

    开始之前先扯点其它的,我上午去理发,居然才7元,但是那个阿妈给我搞成和尚的造型了,我想说点什么,但转念一想节约点洗头水也好!!!

    PS:其实主要原因是我掉头发。。。。。。

    好了,接昨天的内容:【单页应用】一起来单页应用吧,实现简单微博功能!(上)

    昨天我们一起准备了两大核心,继承与view,虽说有问题,而且必定有问题,但是我们暂时不管他。

    我们先继续先往下面写,到最后整体流程拉通后再一起优化就好,现在去纠结也不一定有结果,于是我们开始吧。

    继承之实现APP

    我们这里APP要干的事情,与其说担任MVC中控制器的角色,不如说他就是充当了一下路由选择的角色,根据不同的URL导向不同的view,并且会管理hash。

    由于我们会处理request请求,压入hash以达到后退功能有效,所以这里先来实现一个hash类吧

    实现Hash对象

    先来一个辅助函数,用于计算某个字符在数组的位置:

    复制代码
     1 var indexOf = function (k, arr) {
     2     if (!arr) {
     3         return -1;
     4     }
     5     //若是对象本身便居然indexof,便使用自身的,比如字符串
     6     if (arr.indexOf) {
     7         return arr.indexOf(k);
     8     }
     9     for (var i = 0, len = arr.length; i < len; i++) {
    10         if (arr[i] == k) {
    11             return i;
    12         }
    13     }
    14     return -1;
    15 };
    复制代码

    PS:这个hash的实现不算太好,后面也许会改动

    复制代码
     1 b.Hash = b.Class({
     2     _propertys_: function () {
     3         this.keys = [];
     4         this.values = [];
     5     },
     6     init: function (obj) {
     7         (typeof obj == 'object') || (obj = {}); //???
     8         for (var k in obj) {
     9             if (obj.hasOwnProperty(k)) {
    10                 this.keys.push(k);
    11                 this.values.push(obj[k]);
    12             }
    13         }
    14     },
    15     length: function () {
    16         return this.keys.length;
    17     },
    18     getItem: function (k) {
    19         var index = indexOf(k, this.keys);
    20         if (index < 0) {
    21             return null;
    22         }
    23         return this.keys[index];
    24     },
    25     getKey: function (i) {
    26         return this.keys[i];
    27     },
    28     getValue: function (i) {
    29         return this.values[i];
    30     },
    31     add: function (k, v) {
    32         return this.push(k, v);
    33     },
    34     del: function (k) {
    35         var index = indexOf(k, this.keys);
    36         return this.delByIndex(index);
    37     },
    38     delByIndex: function (index) {
    39         if (index < 0) return this;
    40         this.keys.splice(index, 1);
    41         this.vaules.splice(index, 1);
    42         return this;
    43     },
    44     //移除栈顶hash,并返回
    45     pop: function () {
    46         if (!this.keys.length) return null;
    47         this.keys.pop();
    48         return this.values.pop();
    49     },
    50     push: function (k, v, order) {
    51         if (typeof k == 'object' && !v) {
    52             for (var i in k) {
    53                 if (k.hasOwnProperty(i)) {
    54                     this.push(i, k[i], order);
    55                 }
    56             }
    57         } else {
    58             var index = indexOf(k, this.keys);
    59             if (index < 0 || order) {
    60                 if (order) this.del(k);
    61                 this.keys.push[k];
    62                 this.values.push[v];
    63             } else {
    64                 this.values[index] = v;
    65             }
    66         }
    67     },
    68     //查找hash表,返回key
    69     indexOf: function (v) {
    70         var index = indexOf(v, this.vaules);
    71         if (index >= 0) {
    72             return this.keys[index];
    73         }
    74         return -1;
    75     },
    76     each: function (handler) {
    77         if (typeof handler == 'function') {
    78             for (var i = 0, len = this.length(); i < len; i++) {
    79                 handler.call(this, this.keys[i], this.vaules[i]);
    80             }
    81         }
    82     },
    83     getObj: function () {
    84         var obj = {};
    85         for (var i = 0, len = this.length(); i < len; i++) {
    86             obj[this.keys[i]] = this.values[i];
    87         }
    88         return obj;
    89     }
    90 });
    复制代码

    此hash对象基本就是数组的写照,各位可以对照着看,于是我们继续我们的app

    app雏形

    复制代码
      1 var Application = new b.Class({
      2     _propertys_: function () {
      3         var scope = this;
      4         this.webRoot = ''; //应用跟目录
      5         this.head = $('head');
      6         this.body = $('body');
      7         this.viewRoot = 'views/'; //视图所在目录
      8         this.defaultView = 'index'; //默认加载视图
      9 
     10         this.request; //请求对象
     11         this.viewPath; //当前请求视图路径,解析request得出
     12         this.mainFrame; //主框架
     13         this.viewPort; //视图框架
     14         this.stateDom; //状态栏
     15 
     16         this.views = new b.Hash(); //views保存浏览器存储的hash
     17         this.curView; //当前视图
     18         this.interface = {}; //提供给视图访问的接口,暂时不管
     19         this.history = []; //历史记录
     20 
     21         //        this.stopListening = false;//是否开启监听
     22 
     23         this.onHashChange = function () {
     24             scope.history.push(window.location.href);
     25             var url = decodeURIComponent(window.location.hash.replace(/^#+/i, '')).toLowerCase();
     26             scope._onHashChange(url);
     27         };
     28 
     29         this.lastHash = '';
     30         this.lastFullHash = '';
     31         this.isChangeHash = false; //hash是否发生变化
     32     },
     33     init: function (opts) {
     34         //为属性赋值
     35         opts = opts || {};
     36         for (var k in opts) {
     37             this[k] = opts[k];
     38         }
     39         this.createViewPort();
     40         this.bindEvent(); //事件绑定
     41     },
     42 
     43     //创建app页面基本框架,此处不能使用id,因为。。。
     44     createViewPort: function () {
     45         var htm = [
     46             '<div class="main-frame">',
     47                 '<div class="main-viewport"></div>',
     48                 '<div class="main-state"></div>',
     49             '</div>'
     50         ].join('');
     51         this.mainframe = $(htm);
    
     52         this.viewport = this.mainframe.find('.main-viewport');
     53         this.statedom = this.mainframe.find('.main-state');
     54         var body = $('body');
     55         body.html('');
     56         body.append(this.mainframe);
     57     },
     58     //!!!!!!非常重要哦!!!!!!
     59     bindEvent: function () {
     60         var scope = this;
     61         //暂时不使用requireJS
     62         //        requirejs.onError = function () {};
     63         $(window).bind('hashchange', this.onHashChange);
     64     },
     65     _onHashChange: function (url) {
     66         url = url.replace(/^#+/i, '');
     67         var req = this.parseHash(url);
     68 
     69         this.request = req;
     70         this.viewPath = this.viewPath || this.defaultView;
     71         this.loadView(this.viewPath); //!!!重要的视图加载
     72     },
     73     //该方法慢慢看吧。。。
     74     parseHash: function (hash) {
     75         var fullhash = hash,
     76                 hash = hash.replace(/([^|]*)(?:|.*)?$/img, '$1'),
     77                 h = /^([^?&|]*)(.*)?$/i.exec(hash),
     78                 vp = h[1] ? h[1].split('!') : [],
     79                 viewpath = (vp.shift() || '').replace(/(^/+|/+$)/i, ''),
     80                 path = vp.length ? vp.join('!').replace(/(^/+|/+$)/i, '').split('/') : [],
     81                 q = (h[2] || '').replace(/^?*/i, '').split('&'),
     82                 query = {}, y;
     83         this.isChangeHash = !!(!this.lastHash && fullhash === this.lashFullHash) || !!(this.lastHash && this.lastHash !== hash);
     84         if (q) {
     85             for (var i = 0; i < q.length; i++) {
     86                 if (q[i]) {
     87                     y = q[i].split('=');
     88                     y[1] ? (query[y[0]] = y[1]) : (query[y[0]] = true);
     89                 }
     90             }
     91         }
     92 
     93         this.lastHash = hash;
     94         this.lashFullHash = fullhash;
     95         return {
     96             viewpath: viewpath,
     97             path: path,
     98             query: query,
     99             root: location.pathname + location.search
    100         };
    101     },
    102     //!!!非常重要
    103     loadView: function (viewPath) {
    104         var id = viewPath;
    105         var scope = this;
    106         //此处本来应该判断是否已经有该视图,但是我们暂时不管,我们只要加载了相关视图就算成功
    107         /*
    108         一些操作
    109         */
    110 
    111         //此处应该加载我们的js文件
    112         $.getScript(this.buildUrl(viewPath), function () {
    113             var view = new PageView();
    114             view.show();
    115             scope.viewport.append(curView.$el);
    116             var s = ''; 
    117         });
    118         //!!!暂时不使用requireJS
    119         //        var self = this;
    120         //        requirejs([this.buildUrl(path)], function (View) {
    121         //            callback && callback.call(self, View);
    122         //        });
    123     },
    124     buildUrl: function (path) {
    125         return this.viewRoot = path;
    126     }
    127 });
    复制代码

    好了,至此,我们粗制滥造版app结束,我们来试试先,再一并讲解其主要流程。

    简单测试

    html代码:

    复制代码
     1 <!DOCTYPE html>
     2 <html xmlns="http://www.w3.org/1999/xhtml">
     3 <head>
     4     <meta charset="utf-8" />
     5     <title></title>
     6     <script src="res/libs/jquery.js" type="text/javascript"></script>
     7     <script src="res/test/c.base.js" type="text/javascript"></script>
     8 </head>
     9 <body>
    10 </body>
    11 <script src="res/test/app.js" type="text/javascript"></script>
    12 <script type="text/javascript">
    13     var app = new Application();
    14 
    15 </script>
    16 </html>
    复制代码

    base代码

    复制代码
     base核心
    复制代码

    app代码

    复制代码
     APP
    复制代码

    文件结构

    测试结果

    我可耻的觉得自己成功了一半了。。。

    基本流程讲解

    app是我们整个框架的核心,我们来简单讲解一下:

    ① 在整个_propertys_函数中,定义了我们app会用到的一些实例属性、方法

    ② init方法(一定会执行,因为我们使用了c.base的方法创建类),他主要干了两件事:

    创建基本dom结构;

    绑定事件,这个绑定事件就非常重要了

    ③ 59行开始,便是该文件的核心之一,这里为window绑定了hashchange事件,于是hash一旦改变(以#号方式),那么就会触发onhashchange事件

    ④ 触发hashchange事件后,会获得请求url#后面的参数,根据约定,他就是我们请求的view的路径,所以开始执行loadView方法,开始加载视图

    ⑤ 102行,开始加载视图,这里本应该使用requireJS,但是这里便于讲解,便于各位理解,我们暂时没有使用,于是动态加载我们的index文件,在成功后实例化view并且将view装入我们的视口中。

    ⑥ 整体流程结束

    于是我们的粗制滥造版本也结束了。

    阶段总结

    好了,我们现在回过头来看看我们整个框架现在变成什么样了。

    ① 我们拥有实现类的通用b.class

    ② 我们有了我们的抽象视图类

    ③ 我们有了我们的control application

    假使以上流程都流程问题不大,那么我们整个功能其实就七七八八了,因为还差的model可以轻松补上。

    但是明显我们现在的APP是有缺陷的,而且缺陷比较大,比如我们的hash相关其实根本没有用上,所以现在我们来完善他们吧!

    RequireJS组织代码

    在这里,我们便开始使用我们的RequireJS了,然后将我们的整个逻辑慢慢铺开,首先我将我们的文件目录分开。

    复制代码
     html页
    复制代码
    复制代码
     main
    复制代码
    复制代码
     app
    复制代码
    复制代码
     c
    复制代码
    复制代码
     c.base
    复制代码
    复制代码
     c.view
    复制代码
    复制代码
     index
    复制代码

    至此我们的代码便完全分离开了,接下来我们来细化我们的app文件。

    细化app

    待续......

    结语

    写了几个小时了,有点累,休息下,我们晚上在继续

     
     
    分类: 移动开发
    标签: 单页应用
  • 相关阅读:
    五:系统及数据库
    四:WEB源码扩展
    三:搭建安全拓展
    二:数据包扩展
    一:基础入门-概念名词
    LeetCode 11. Container With Most Water
    LeetCode 263. Ugly Number
    LeetCode 10. Regular Expression Matching
    LeetCode 58. Length of Last Word
    LeetCode 53. Maximum Subarray
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3251820.html
Copyright © 2020-2023  润新知