收藏本站腾讯微博新浪微博

经典论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

蓝色理想 最新研发动态 网站开通淘帖功能 - 蓝色理想插件 论坛内容导读一页看论坛 - 给官方提建议

论坛活动及任务 地图和邮件任务 请多用悬赏提问 热夏来袭,选一款蓝色理想的个性T恤吧!

手机上论坛,使用APP获得更好体验 急需前端攻城狮,获得内部推荐机会 论坛开通淘帖功能,收藏终于可以分类了!

搜索
查看: 2390|回复: 2

Javascript以面向对象的思路实现可切换的页面控件

[复制链接]
发表于 2010-8-30 21:50:21 | 显示全部楼层 |阅读模式
本篇文章的主要目的是使用Javascript以面向对象的思想从另外一个角度去实现一系列页面控件。

首先声明一下:

1.如果你只是想要一个完善的js代码,让你可以套用到自己的页面并立即实现你想要的效果,为了节省你的时间,请绕过。

2.如果你想看一篇手把手的给你实现一个标签页效果或者轮换图片的效果,那么请路过。

3.如果你喜欢Javascript这个语言,想一起思考一些更深入的东西,请继续阅读并希望你不吝赐教。

点击查看演示效果(Demo比较粗糙,兼容IE6+,FX3.5+,只能说勉勉强强的支持IE6,这里不着重讨论兼容性,还请海涵)

其实自从jQuery火起来之后,很多以前我们实现起来很复杂的效果现在很轻松的就能实现了,这带给了我们极大的方便,但是同时也让我们变得懒惰,变得不爱思考。它让我们的代码在变得简洁的同时也变得不那么“干净”,我们可能会随手写一些实现效果的代码,而不是深入的去思考。当然jQuery本身没错,只不过我自己变懒了而已。当然话又说回来,“懒惰”是让程序员进步的原动力:P

言归正传,在这篇文章里我想和大家一起讨论一下页面中常见的几种页面控件的实现,例如:标签页控件,轮播的幻灯控件,还有土豆网下面那种用滚动条控制的一行影片列表等等。其实这些页面控件它们实际上的行为都很类似,所以我们这里讨论的其实是一类控件,我给它取了一个名字叫“可切换”控件。下面就分析一下我为什么要这么说。

这类控件它们的共性就是,都有内容展示区(废话,没内容还做毛啊)和一个类似导航器的元素。

这个内容展示区并不是说单纯的文字或图片放在那,这个内容展示区是由几部分结构或表现形式十分类似的内容区共同组成的,而且这几部分内容一般情况下不是同时显示出来,而是在用户触发或者系统定义的条件出发下才会轮换显示,也就是我们前面提到的“可切换”的。

另外它们一般都还会有一个控制器,或者说是导航器,抑或者是标签,不管什么名字,我这里称之为“向导”(guider),藉由这个向导我们能够定位到我们想要看到的内容上,这个向导可能是“1,2,3…”这个样子的,也可能能是“上一个,下一个”这个样子的,也有可能是“标签一,标签二”这个样子,无论它的表现形式是什么样,它的作用都是非常类似的。

通过上面简单的分析我们可以得出这类控件的共性,下面我们会用到这个共性来实现我们的“可切换”(switchable)对象。

下面我先提一点老生常谈的东西。我们在提起面向对象的时候,我们的对象要包含属性和方法等,其实作为一组行为也可以看作为对象的,在设计模式的策略模式中,我们把对象的行为抽取出来作为一个新的对象来处理不就是把一组行为作为一个对象吗?所以我们这里就要抽象出一个switchable对象来,让我们页面中具有“可切换”能力的对象来继承这个对象。

让我们看一下我们的switchable对象都具有哪些行为。



来看一下这几个属性分别代表的意义和它们的作用。

guiderStatus:bool值,用于控制gider是否显示
guider:HTML元素,是“向导”的容器
guiderDoms:HTML元素数组,是“向导”的各个条目
panel:HTML元素,是内容显示区的容器
panelDoms:HTML元素数组,内容显示区的各个条目
currID:控制句柄,当前显示的内容条目的ID
totalNum:总共有多少个内容条目

下面是方法,首先是init初始化方法,这个方法是用于遍历制定的DOM下的子节点,按照固有的规则或约定,将HTML元素的引用付给相对应的属性。并控制guider是否显示。

其次是initGuiderEvent初始化向导事件方法,给向导的每一个条目注册事件。

再次是 beforeShow,afterShow,showItem,hideItem,focusGuider,blurGuider这六个虚方法,这六个方法是需要在继承与switchable这个类的子类里面按照需要重写的方法,在guiderClickEvent这个事件方法中调用了上述的几个方法,这里用的是一个简单的模板方法模式。

最后的就是showNext和showPreview这两个通用的显示下一个和显示上一个方法。同样调用的是上述的六个虚方法的组合。

下面我们就在此基础上实现标签页控件。

  1. var tabcomponent = function(tabId, classNames){
  2.         switchable.call(this);
  3.         this.guiderStatus = true;
  4.         if (classNames) {
  5.                 this.guiderClassName = classNames.guider;
  6.                 this.guiderDomsClassName = classNames.guiderDoms;
  7.                 this.panelClassName = classNames.panel;
  8.                 this.panelDomsClassName = classNames.panelDoms;
  9.         }
  10.         this.init(tabId);
  11. }

  12. tabcomponent.prototype = new switchable();

  13. tabcomponent.prototype.showItem = function(i){
  14.         this.resetPanelStatus();
  15.         this.panelDoms[i].style.display = 'block';
  16. }
  17. tabcomponent.prototype.hideItem = function(i){
  18.         this.panelDoms[i].style.display = 'none';
  19. }
  20. tabcomponent.prototype.focusGuider = function(i){
  21.         this.resetGuiderStatus();
  22.         this.guiderDoms[i].className = 'active';
  23. }
  24. tabcomponent.prototype.blurGuider = function(i){
  25.         this.guiderDoms[i].className = '';
  26. }
  27. tabcomponent.prototype.resetPanelStatus = function(){
  28.         for (var i in this.panelDoms) {
  29.                 this.hideItem(i);
  30.         }
  31. }
  32. tabcomponent.prototype.resetGuiderStatus = function(){
  33.         for (var i in this.panelDoms) {
  34.                 this.blurGuider(i);
  35.         }
  36. }
复制代码


首先设置guideStatus为true,让guider为显示状态。然后我们重写了showItem,hideItem,focustGuider,blurGuider这四个方法,这里没有添加特殊的效果,showItem就是设置相对应的Dom的显示值为block,hideItem则是none。同样我们还添加了两个方法,resetPanelStatus和resetGuiderStatus两个方法,用于每次显示前重置相关的元素的显示状态。实现就是这么的简单。同样幻灯片控件大家可以看一下源码,也是比较简单。

  1. var slidecomponent = function(id){   
  2.     this.guiderStatus = true;   
  3.     this.timer = null;   
  4.     this.delayTime = 3000;   
  5.     this.init(id);   
  6.     this.slideInit();   
  7. }   
  8.   
  9. slidecomponent.prototype = new switchable();   
  10.   
  11. slidecomponent.prototype.slideInit = function(){   
  12.     this.panel.style.width = $$(this.panelDoms[0]).css('width');   
  13.     this.panel.style.height = $$(this.panelDoms[0]).css('height');   
  14.     this.panelHeight = parseInt(this.panel.style.height);   
  15.     this.timer = setInterval(dk.bind(this,this.showNext),this.delayTime);   
  16. }   
  17. slidecomponent.prototype.beforeShow = function(){   
  18.     clearInterval(this.timer);   
  19. }   
  20. slidecomponent.prototype.afterShow = function(){   
  21.     this.timer = setInterval(dk.bind(this,this.showNext),this.delayTime);   
  22. }   
  23. slidecomponent.prototype.showItem = function(i){   
  24.     mo(this.panel).animate({'scrollTop':this.panelHeight*i},mo.fast);   
  25. }   
  26. slidecomponent.prototype.resetGuiderStatus = function(){   
  27.     for(var i in this.panelDoms){   
  28.         this.blurGuider(i);   
  29.     }   
  30. }   
  31. slidecomponent.prototype.focusGuider = function(i){   
  32.     this.resetGuiderStatus();   
  33.     this.guiderDoms[i].className = 'active';   
  34. }   
  35. slidecomponent.prototype.blurGuider = function(i){   
  36.     this.guiderDoms[i].className = '';   
  37. }  
  38. var slidecomponent = function(id){
  39.         this.guiderStatus = true;
  40.         this.timer = null;
  41.         this.delayTime = 3000;
  42.         this.init(id);
  43.         this.slideInit();
  44. }

  45. slidecomponent.prototype = new switchable();

  46. slidecomponent.prototype.slideInit = function(){
  47.         this.panel.style.width = $$(this.panelDoms[0]).css('width');
  48.         this.panel.style.height = $$(this.panelDoms[0]).css('height');
  49.         this.panelHeight = parseInt(this.panel.style.height);
  50.         this.timer = setInterval(dk.bind(this,this.showNext),this.delayTime);
  51. }
  52. slidecomponent.prototype.beforeShow = function(){
  53.         clearInterval(this.timer);
  54. }
  55. slidecomponent.prototype.afterShow = function(){
  56.         this.timer = setInterval(dk.bind(this,this.showNext),this.delayTime);
  57. }
  58. slidecomponent.prototype.showItem = function(i){
  59.         mo(this.panel).animate({'scrollTop':this.panelHeight*i},mo.fast);
  60. }
  61. slidecomponent.prototype.resetGuiderStatus = function(){
  62.         for(var i in this.panelDoms){
  63.                 this.blurGuider(i);
  64.         }
  65. }
  66. slidecomponent.prototype.focusGuider = function(i){
  67.         this.resetGuiderStatus();
  68.         this.guiderDoms[i].className = 'active';
  69. }
  70. slidecomponent.prototype.blurGuider = function(i){
  71.         this.guiderDoms[i].className = '';
  72. }
复制代码

写到这里这篇文章也就写完了,当然这只是一个雏形,要想提高开发效率,肯定得继续进行大量的完善工作,比如guider绑定的事件类型应该也是可以定制的,方法模板也可能需要进一步的完善,对dom结构的定制性也需要进一步的完善。

甚至我们还可以维护一个dragable对象,只要继承了dragable对象,实现了相应的接口,我们的标签页控件里面就变成一个可拖动的标签页,想想是不是很有意思呢。

这里只是先提供了一个思路,希望对大家在往后的开发中能有一点抛砖引玉的作用,大家有什么观点请不吝赐教。

源代码都在演示页面里面啦,就不再打包上传啦,包涵。

查看原文
 楼主| 发表于 2010-8-31 09:38:03 | 显示全部楼层

回复 3# zhutianyi 的帖子

是一个虚函数,借鉴了模板模式的一些思想,目前实现的比较简单,而且没有做进一步的抽象,内部的行为应该也可以用组合实现,要是做的这种模板类多了可以进一步抽象。
回复 支持 反对

使用道具 举报

发表于 2010-9-2 21:19:52 | 显示全部楼层
-  - 我还以为什么新花样,早知道绕行了。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

QQ|小黑屋|Archiver|手机版|blueidea.com ( 湘ICP备12001430号 )  

GMT+8, 2020-7-15 01:49 , Processed in 0.109100 second(s), 9 queries , Gzip On, Memcache On.

Powered by Discuz! X3.2 Licensed

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表