仿网易邮箱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了。效果图如下:

原文地址:https://www.cnblogs.com/AUOONG/p/2824114.html