• 仿网易邮箱5.0(三):panel.js


    今天我们首先来接触第一个用到的插件--Neter.Panel(登录框),在这个插件中,主要的操作有:添加一个标签,更新标签,删除标签。
    还是先上代码:

    View Code
      1 /**
      2  * 面板插件,支持多标签,很像TabPanel,但与之不同的在于标签宽度是平分
      3  * 并且不支持url,内容仅能为html(当然,可以自己在此基础之上进行扩展)
      4  * @author Ly
      5  * @date 2012/11/14
      6  */
      7 ;Neter.namespace('Neter.Panel');
      8 
      9 /**
     10  * @class
     11  * @name Neter.Panel
     12  * @param {Object} options 自定义配置信息
     13  <pre>
     14  options = {
     15     width      : 340,
     16     height     : 390,
     17     defaultTag : 0,
     18     container  : document.body,     // 面板容器,即将面板放于哪个元素之内,默认为body
     19     bodies     : [{                 // 面板主体,至少包含一个元素
     20         tag        : '',
     21         content    : ''
     22     }],
     23     activeType : 'hover'            // 激活标签的方式,hover/click,默认为hover,即鼠标滑过则切换
     24  }
     25  </pre>
     26  */
     27 ;Neter.Panel = function(options) {
     28     var _this = this;
     29     
     30     this.defaults = {
     31         width      : 340,
     32         height     : 390,
     33         defaultTag : 0,
     34         container  : document.body,     // 面板容器,即将面板放于哪个元素之内,默认为body
     35         bodies     : [{                 // 面板主体,至少包含一个元素
     36             tag     : '',
     37             content : ''
     38         }],
     39         activeType : 'hover'            // 激活标签的方式,hover/click,默认为hover,即鼠标滑过则切换
     40     };
     41     
     42     Neter.apply(this.defaults, options, {
     43         // 边框宽度
     44         BORDER_WIDTH : 2
     45     });
     46     
     47     this.handler = {
     48         container     : $(this.defaults.container),
     49         panel         : null,
     50         tagBar        : null,
     51         viewContainer : null,
     52         bodies        : [],
     53         previous      : {
     54             tag  : null,
     55             view : null
     56         }
     57     };
     58     
     59     this.defaults.container = null;
     60     
     61     this.method = {
     62         /**
     63          * 创建插件框架
     64          * @ignore
     65          */
     66         create : function() {
     67             var defaults  = _this.defaults,
     68                 handler   = _this.handler;
     69             
     70             // 创建面板容器
     71             handler.panel = $('<div></div>').addClass('neter-panel')
     72                 .appendTo(handler.container);
     73             
     74             // 创建标签栏
     75             handler.tagBar = $('<div></div>').addClass('neter-panel-tag-bar')
     76                 .appendTo(handler.panel);
     77             
     78             // 创建主体
     79             handler.viewContainer = $('<div></div>').addClass('neter-panel-view-container')
     80                 .appendTo(handler.panel);
     81             
     82             return this;
     83         },
     84         /**
     85          * 初始化布局,当添加与删除标签时也需要调用此方法来重新进行页面布局初始化
     86          * @ignore
     87          */
     88         initLayout : function() {
     89             var defaults      = _this.defaults,
     90                 handler       = _this.handler,
     91                 width         = defaults.width - defaults.BORDER_WIDTH,
     92                 height        = defaults.height - defaults.BORDER_WIDTH,
     93                 tagBar        = handler.tagBar.css({ width : width }),
     94                 bodies        = handler.bodies,
     95                 tagWidth      = tagBar.width() / bodies.length,
     96                 viewContainer = handler.viewContainer;
     97             
     98             handler.panel.css({ width : width, height : height });
     99             
    100             handler.viewContainer.css({
    101                 width  : width,
    102                 height : height - tagBar.outerHeight()
    103             });
    104             
    105             $.each(bodies, function(index, value) {
    106                 value.tag.css({ borderRightWidth : '1px', width : tagWidth - 1 });
    107             });
    108             
    109             tagBar.find('.neter-panel-tag:last').css({
    110                 borderRightWidth : 0,
    111                 width            : tagWidth
    112             });
    113             
    114             return this;
    115         },
    116         /**
    117          * 插入面板标签,如果参数都省略,则取this.defaults.bodies中的内容
    118          * @ignore
    119          * @param {Number} index 新加入的标签位置,值为-1时直接添加到最后
    120          * @param {Object} options 新加入的内容,{ tag : '', content : '' }
    121          */
    122         insert : function(index, options) {
    123             var defaults      = _this.defaults,
    124                 handler       = _this.handler,
    125                 tagBar        = handler.tagBar,
    126                 viewContainer = handler.viewContainer,
    127                 bodies        = handler.bodies;
    128             
    129             arguments.length && defaults.bodies.push(options);
    130             
    131             $.each(defaults.bodies, function(i, options) {
    132                 var tag = $('<div></div>').addClass('neter-panel-tag').html(options.tag),
    133                     view = $('<div></div>').addClass('neter-panel-view').append(options.content);
    134                 
    135                 if (typeof index === 'number') {
    136                     index = !~index ? bodies.length : index;
    137                     var tmp = tagBar.find('.neter-panel-tag')[index];
    138                     
    139                     tmp ? tag.insertBefore(tmp) : tagBar.append(tag);
    140                     
    141                     (tmp = viewContainer.find('.neter-panel-view')[index])
    142                         ? view.insertBefore(tmp)
    143                         : viewContainer.append(view);
    144                     
    145                     bodies.splice(index, 0, { tag : tag, view : view, options : options });
    146                 } else {
    147                     tagBar.append(tag);
    148                     viewContainer.append(view);
    149                     bodies.splice(i, 0, { tag : tag, view : view, options : options });
    150                 }
    151             });
    152             
    153             defaults.bodies = [];
    154             
    155             return this;
    156         },
    157         /**
    158          * 更新标签内容
    159          * @ignore
    160          * @param {Number} index 要更新的标签所处的位置
    161          * @param {Object} options 新标签的内容,{tag : '', content : '' }
    162          */
    163         update : function(index, options) {
    164             var defaults = _this.defaults,
    165                 handler  = _this.handler,
    166                 dest     = handler.bodies[index];
    167             
    168             if (dest) {
    169                 dest.tag.html(options.tag);
    170                 dest.view.empty().append(options.content);
    171                 dest.options = options;
    172             }
    173             
    174             return this;
    175         },
    176         /**
    177          * 删除指定的标签
    178          * @ignore
    179          * @param {Number} index 要删除的标签,可一次性删除多个标签
    180          */
    181         remove : function(index) {
    182             var defaults = _this.defaults,
    183                 handler  = _this.handler,
    184                 dest     = handler.bodies[index];
    185             
    186             if (dest) {
    187                 dest.tag.remove();
    188                 dest.view.empty().remove();
    189                 
    190                 handler.bodies[index].tag  = null;
    191                 handler.bodies[index].view = null;
    192                 handler.bodies.splice(index, 1);
    193             }
    194             
    195             return this;
    196         },
    197         /**
    198          * 给标签绑定切换事件,至于激活标签的方式由this.defaults.activeType来指定
    199          * @ignore
    200          */
    201         bindEvents : function() {
    202             var defaults = _this.defaults,
    203                 handler  = _this.handler,
    204                 current  = handler.current;
    205             
    206             handler.tagBar.on(defaults.activeType, 'div.neter-panel-tag', function() {
    207                 _this.method.active(this);
    208             });
    209             
    210             return this;
    211         },
    212         /**
    213          * 激活标签
    214          * @ignore
    215          * @param {HTMLElement} current 要切换到的标签,是一个dom对象
    216          */
    217         active : function(current) {
    218             var defaults = _this.defaults,
    219                 handler  = _this.handler,
    220                 previous = handler.previous;
    221             
    222             previous.tag && previous.tag.removeClass('neter-panel-tag-current');
    223             previous.view && previous.view.hide();
    224             
    225             previous.tag = $(current).addClass('neter-panel-tag-current');
    226             
    227             $.each(handler.bodies, function(index, value) {
    228                 if (value.tag.get(0) === current) {
    229                     previous.view = value.view.show();
    230                 }
    231             });
    232             
    233             return this;
    234         }
    235     };
    236 };
    237 
    238 ;Neter.apply(Neter.Panel.prototype, {
    239     /**
    240      * 渲染插件
    241      * @function
    242      * @name Neter.Panel.prototype.render
    243      * @return {Neter.Panel} 返回插件引用
    244      */
    245     render : function() {
    246         this.method.create().insert().initLayout().bindEvents();
    247         
    248         this.active(this.defaults.defaultTag);
    249         
    250         return this;
    251     },
    252     /**
    253      * 获取Panel本身
    254      * @function
    255      * @name Neter.Panel.prototype.get
    256      * @return {jQueryDOM} 返回插件DOM对象,经过jQuery封装。
    257      */
    258     get : function() {
    259         return this.handler.panel;
    260     },
    261     /**
    262      * 获取Panel视图
    263      * @function
    264      * @name Neter.Panel.prototype.getView
    265      * @return {jQueryDOM} 返回插件视图DOM对象,经过jQuery封装。
    266      */
    267     getView : function() {
    268         return this.handler.viewContainer;
    269     },
    270     /**
    271      * 激活标签
    272      * @function
    273      * @name Neter.Panel.prototype.active
    274      * @param {Number} [index=0] 要激活的标签,从0开始,默认为0
    275      * @return {Neter.Panel} 返回插件引用
    276      */
    277     active : function(index) {
    278         this.method.active(this.handler.tagBar.find('>div').get(index || 0));
    279         
    280         return this;
    281     },
    282     /**
    283      * 插入一个标签,默认为放在最后
    284      * @function
    285      * @name Neter.Panel.prototype.insert
    286      * @param {Number} index 新加入的标签位置,默认为最后
    287      * @param {Object} options 新加入的内容,{ tag : '', content : '' }
    288      * @return {Neter.Panel} 返回插件引用
    289      */
    290     insert : function(index, options) {
    291         // 当仅有一个options参数时
    292         if (typeof index == 'object') {
    293             index   = -1;
    294             options = index;
    295         }
    296         index = typeof index === 'number' ? index : -1;
    297         
    298         if (!options || !options.hasOwnProperty('tag') || !options.hasOwnProperty('content')) { return this; }
    299         
    300         this.method.insert(index, options).initLayout();
    301         
    302         return this;
    303     },
    304     /**
    305      * 更新标签内容
    306      * @function
    307      * @name Neter.Panel.prototype.update
    308      * @param {Number} index 要更新的标签所处的位置
    309      * @param {Object} options 新标签的内容,{tag : '', content : '' }
    310      * @return {Neter.Panel} 返回插件引用
    311      */
    312     update : function(index, options) {
    313         if (index < 0 || !options || !options.hasOwnProperty('tag') || !options.hasOwnProperty('content')) { return this; }
    314         
    315         this.method.update(index, options);
    316         
    317         return this;
    318     },
    319     /**
    320      * 删除指定的标签
    321      * @function
    322      * @name Neter.Panel.prototype.remove
    323      * @param {Number} index 要删除的标签,可一次性删除多个标签
    324      * @return {Object} null
    325      */
    326     remove : function(index) {
    327         var _this = this;
    328         $.each([].slice.call(arguments, 0).sort().reverse(), function(i, index) {
    329             index > -1 && _this.method.remove(index);
    330         });
    331         
    332         this.method.initLayout();
    333         
    334         // 删除标签后,切换到当前的标签,这样可以使得删除当前标签后不至于没有被显示的标签
    335         this.active(this.defaults.defaultTag);
    336         
    337         return null;
    338     }
    339 });

    既然要仿网易的标签,那么操作上也要支持嘛,网易的登录框标签的切换是鼠标悬念,因此在这里也提供了一个配置参数activeType,默认就是hover。
    下面就是仿制过程了。:)
    1、先来看一下HTML结构:

     1 <div id="center">
     2     <div id="container">
     3         <div id="login"></div>
     4     </div>
     5 </div>
     6 
     7 <!-- #account块是用来初始化登录框的 -->
     8 <div id="account">
     9     <div class="field-container"><input type="text" id="username" class="neter-input-gray" placeholder="邮箱帐号或手机号" /></div>
    10     <div class="field-container"><input type="password" id="password" class="neter-input-gray" placeholder="密码" /></div>
    11     <div class="field-container">
    12         <input type="checkbox" id="autoLoginOptions" autocomplete="off" /><label for="autoLoginOptions">最近两周自动登录</label>
    13     </div>
    14     <div class="field-container">
    15         <input id="loginBtn" type="button" value="登 录" class="neter-button-large neter-button-large-primary" />
    16         <input id="regBtn" type="button" value="注 册" class="neter-button-large reg" />
    17     </div>
    18 </div>

    以上这块代码就是整个登录页面的HTML代码。不过这里仅做了关于邮箱名登录的,至于手机的自己再搞定。
    之所以div#center里面还有#container与#login,主要是为了展现一下网易邮箱登录页面中的刷新切换背景图片。下面的#account就是给panel中的账号登录准备的。
    2、在js中实例化Neter.Panel。

     1 ;$(function() {
     2     var panel = new Neter.Panel({
     3         container : $('#login'),
     4         bodies    : [{
     5             tag     : '邮箱账号登录',
     6             content : $('#account')
     7         }, {
     8             tag     : '手机号登录',
     9             content : '手机号登录面板...'
    10         }]
    11     }).render();
    12 });

    简单吧,这样就ok了。效果图如下:

  • 相关阅读:
    Android和iOS的APP测试区别
    APP强制更新、非强制更新的测试要点(转)
    (转)mongodb与mysql区别
    接口测试注意事项参考
    测试Checklist参考
    ADB:运行adb shell uiautomator dump并查看dump文件,由于权限问题报错的解决办法
    运行adb devices显示List of devices attached,无法获取模拟器设备信息的解决办法
    Python实现进度条
    移动APP自动化测试框架对比(转)
    Cortex-M0总结
  • 原文地址:https://www.cnblogs.com/AUOONG/p/2824114.html
Copyright © 2020-2023  润新知