论坛交流
首页办公自动化| 网页制作| 平面设计| 动画制作| 数据库开发| 程序设计| 全部视频教程
应用视频: Windows | Word2007 | Excel2007 | PowerPoint2007 | Dreamweaver 8 | Fireworks 8 | Flash 8 | Photoshop cs | CorelDraw 12
编程视频: C语言视频教程 | HTML | Div+Css布局 | Javascript | Access数据库 | Asp | Sql Server数据库Asp.net  | Flash AS
当前位置 > 文字教程 > Javascript教程
Tag:验证,特效,入门,实例,验证,表单,特效,正则表达式,跑马灯,document,函数,代码,getElementByID,菜单,图片,视频教程

使用JavaScript创建可维护的幻灯片效果

文章类别:Javascript | 发表日期:2010-6-26 14:23:13

第一步:分析问题(Analizing the problem)

创建一个好的脚本,第一步应该是去分析哪些是你要完成的:我们想要创建一个照片的幻灯片效果,并且我们想要保持维护的方便。

如何创建一个幻灯片效果

在一个网站上拥有幻灯片有几种方法:


  • 在文档中包含所有的图片。当他运行在无 JavaScript 状态,这是一个安全的选择。而且,当页面被载完,所有的图片也会将被载完。然而,这个方式只适用于少量的图片。

  • 在文档中包含第一张图片,并且有一个创建幻灯片功能的服务器端脚本。这也是相当安全的,但是对于终端用户来说,这是非常令人厌烦的——因为我不想加载整个页面,仅想得到下一张照片。但对页面展示和广告点击比较有效,这也是为什么大量的新闻站点使用这个方法。

  • 在文档中包含第一张图片,并按需加载其他图片。这个方法令你厌烦的是,必须依赖于 JavaScript ,并且要有一个维护照片列表的 JavaScript 数组。你还需提供一个加载指示器,用来显示用户一些正在发生的事情。



在我们的案例中,我们采取下面的图片列表,用向前和向后的按钮把他变成一个幻灯片效果,并且一个指示器告诉我们,照片总数中的哪张照片是当前显示的。

复制内容到剪贴板
代码:
<ul id="slideshow">
    <li><img src="img/flat1.jpg" alt="Hallway" /></li>
    <li><img src="img/flat2.jpg" alt="Hob" /></li>
    <li><img src="img/flat3.jpg" alt="Bathroom" /></li>
    <li><img src="img/flat4.jpg" alt="Living Room" /></li>
    <li><img src="img/flat5.jpg" alt="Bedroom" /></li>
</ul>

最后的输出会看起来像例子中的幻灯片效果。

依赖关系检查

我们这里有一些元素依赖于 JavaScript 生成:文字指示器和向前和向下的链接。为了保持我们解决方法的可用性,我们需要确保一些事情:


  • 仅当 JavaScript 可用(用户信赖我们提供给他们使用的功能)时,这些元素应该出现。一个链接,不能做任何违反用户对我们的信任的事情。
  • 不论输入设备(让我们不要依赖用户是否有鼠标),交互式元素都应该可用。
  • 图片不应该被隐藏,除非使用者能再次访问他们。在技术上,仅显示第一张图片,且没有向前和向后的链接是预留退路的做法,但是为什么要用户已下载所有的图片仅只看到第一张?



第二步:规划脚本(Planning the Script)

一旦你已经评估了问题,并挑选出你想使用的解决方法,你便可以开始规划脚本。本质上,我们的脚本应该做这些:


  • 检查幻灯片列表是否存在,并且包含一些图片(有理由为一张图片创建一个幻灯片效果吗?)。
  • 隐藏所有的照片,但不是第一个。
  • 创建向前和向后的链接,和一个显示我们在哪的指示器。
  • 添加事件处理程序,使链接增加或减少当前显示的图片编号。
  • 确保幻灯片效果没有超出范围,当图片编号小于 0 ,他应该变为最后一张图片,反过来类似。



不同的功能处理

我们有一些方法处理这个问题。其中之一是使用 DOM 遍历每个 LI 条目并隐藏他。在这个事件监听函数,我们先隐藏先前显示的 LI (如果有的话),并显示当前的这个。

注:显示和隐藏代替图片的 LI 更有意义,因为他允许维护者在每个幻灯片上添加其他的元素,比如,一些标题。

这个方法的问题在于,我们在 JavaScript 中做必要的样式改变,这意味着如果有需要比刚才我们脚本中改变 display 从 block 到 none 更复杂的样式改变,将使脚本变得更杂乱(没有从行为中分离表现)。

样式留给 CSS 解析器

更简洁的方法是将所有的外观改变(在所有列表项下载完之后隐藏某些)都留给浏览器的 CSS 解析器。在我们的例子中,我们可以在幻灯片中使用一个 CSS 规则很容易地隐藏所有的列表项,并用一个特定的 class 重写当前条目的样式。

HTML:

复制内容到剪贴板
代码:
<ul id="slideshow">
    <li><img src="img/flat1.jpg" alt="Hallway" /></li>
    <li><img src="img/flat2.jpg" alt="Hob" /></li>
    <li><img src="img/flat3.jpg" alt="Bathroom" /></li>
    <li><img src="img/flat4.jpg" alt="Living Room" /></li>
    <li><img src="img/flat5.jpg" alt="Bedroom" /></li>
</ul>

CSS:

复制内容到剪贴板
代码:
#slideshow li{
    display:none;
}
#slideshow li.current{
    display:block;
}

唯一的问题是,如果我们使 CSS 和 JavaScript 不可用,访客将永远不能访问到其他图片。因此,我们需要仅当 JavaScript 可用时,应用这些样式。技巧是,当 JavaScript 可用,在幻灯片的 UL 上应用 class ,例如名为 js 。这允许我们仅当 JavaScript 可用时,显示效果,通过在 CSS 中简单的修改:

CSS:

复制内容到剪贴板
代码:
#slideshow.js li{
    display:none;
}
#slideshow.js li.current{
    display:block;
}

这个 class 的钩子(hook)也能被用来对幻灯片的静态和动态版本提供一个完全不同的外观。

我们所有的脚本需要做的是,通过移除或添加 current 的 class 来显示和隐藏当前及以前的照片。

为了确保我们的脚本将不会影响同一页面上的其他脚本,我们将创建一个主要的对象,并在其上构造所有的方法和属性。这可以确保我们的 init() 函数将不会被覆盖或覆盖其他任何相同名字的函数。

JavaScript:

复制内容到剪贴板
代码:
slideshow = {
    current:0, // 当前幻灯片编码
    init:function(){
        // 初始化和设置事件处理函数
    },
    show:function(e){
        // 事件监听器
    }
}

第三步、基本的工具方法( Essential Tools)

现在,我们有了规划和建立我们脚本的框架。是时候思考我们需要完成这个功能的一些工具方法。在其最低要求的情况下,DOM 脚本的帮助库应该包括:


  • 一个注册事件处理函数的方法,我们目前将使用 John Resig 的 addEvent() 方法。
  • 添加和移除 CSS 样式名的方法。
  • 一个覆盖 HTML 元素默认行为的方法。我们不希望出现链接的目标页,而仅是执行脚本。
  • 我们添加这些工具方法到主要的对象上,并准备开始:



JavaScript:

复制内容到剪贴板
代码:
slideshow = {
    current:0, // 当前幻灯片编码
    init:function(){
        // 初始化和设置事件处理函数
    },
    show:function(e){
        // 事件监听器
    },
    addEvent:function( obj, type, fn ) {
        if ( obj.attachEvent ) {
            obj['e'+type+fn] = fn;
            obj[type+fn] = function(){
                obj['e'+type+fn]( window.event );
            }
            obj.attachEvent( 'on'+type, obj[type+fn] );
        } else
            obj.addEventListener( type, fn, false );
    },
    removeClass:function(o,c){
        var rep=o.className.match(' '+c)?' '+c:c;
        o.className=o.className.replace(rep,”);
    },
    addClass:function(o,c){
        var test = new RegExp("(^|\\s)" + c + "(\\s|$)").test(o.className);
        if(!test){o.className+=o.className?’ ‘+c:c;}
    },
    cancelClick:function(e){
        if (window.event){
            window.event.cancelBubble = true;
            window.event.returnValue = false;
        }
        if (e && e.stopPropagation && e.preventDefault){
            e.stopPropagation();
            e.preventDefault();
        }
    }
}

当文档完全载完,第一件事情就是需要执行 init() 方法:

JavaScript:

复制内容到剪贴板
代码:
slideshow = {
    current:0, // 当前幻灯片编码
    init:function(){
        // 初始化和设置事件处理函数
    },
    show:function(e){
        // 事件监听器
    },
    addEvent:function( obj, type, fn ) {
        if ( obj.attachEvent ) {
            obj['e'+type+fn] = fn;
            obj[type+fn] = function(){
                obj['e'+type+fn]( window.event );
            }
            obj.attachEvent( 'on'+type, obj[type+fn] );
        } else
            obj.addEventListener( type, fn, false );
    },
    removeClass:function(o,c){
        var rep=o.className.match(' '+c)?' '+c:c;
        o.className=o.className.replace(rep,”);
    },
    addClass:function(o,c){
        var test = new RegExp("(^|\\s)" + c + "(\\s|$)").test(o.className);
        if(!test){o.className+=o.className?’ ‘+c:c;}
    },
    cancelClick:function(e){
        if (window.event){
            window.event.cancelBubble = true;
            window.event.returnValue = false;
        }
        if (e && e.stopPropagation && e.preventDefault){
            e.stopPropagation();
            e.preventDefault();
        }
    }
}
slideshow.addEvent(window,'load',slideshow.init);

第四步:脚本(The Script)

现在,在适当的位置我们有所有的方法工具,以及当窗口载完时被调用的 init() ,我们可以开始具体化此方法。

注:这仅是 init() 方法,而不是整个脚本。因为有行号,复制并粘贴脚本将会导致错误。

复制内容到剪贴板
代码:
1: init:function(){
2:     if(document.getElementById && document.createTextNode){
3:         var list = document.getElementById(' ');
4:         if(list){
5:             slideshow.items = list.getElementsByTagName('li');
6:             slideshow.all = slideshow.items.length;
7:             if(slideshow.all > 1){
8:                 slideshow.addClass(list, 'js');
9:                 slideshow.createNav(list);
10:            }
11:         }
12:         slideshow.show();
13:     }
14: },

  • 第2行,检测 DOM 是否被支持。
  • 第3和4行,尝试检索 ID 为 slideshow 的元素,如果没有被定义则不执行余下的方法。
  • 第5和6行,检索列表项及列表项的个数,并分别储存在属性 items 和 all 里。
  • 第7行,检测是否超多一个列表项,如果不超多则不执行余下的。
  • 第8行,添加 js 样式类名到列表上,从而隐藏列表项和应该不同的样式。
  • 第9行,调用 createNav(),并提供这个列表作为参数。
  • 第12行,调用 show() 用来显示预定义了 current 属性的滑动门。



createNav() 方法使用 DOM 脚本创建幻灯片正常工作所需的 HTML。

复制内容到剪贴板
代码:
1: createNav:function(o){
2:     var p = document.createElement('p');
3:     slideshow.addClass(p, 'slidenav');
4:     slideshow.prev = document.createElement('a');
5:     slideshow.prev.setAttribute('href', '#');
6:     var templabel = document.createTextNode('<<');
7:     slideshow.prev.appendChild(templabel);
8:     slideshow.addEvent(slideshow.prev, 'click', slideshow.show);
9:     p.appendChild(slideshow.prev);
10:     slideshow.count = document.createElement('span');
11:     templabel = document.createTextNode( (slideshow.current+1) + ' / ' + slideshow.all);
12:     slideshow.count.appendChild(templabel);
13:     p.appendChild(slideshow.count);
14:     slideshow.next = document.createElement('a');
15:     slideshow.next.setAttribute('href', '#');
16:     var templabel = document.createTextNode('>>’);
17:     slideshow.next.appendChild(templabel);
18:     slideshow.addEvent(slideshow.next, ‘click’, slideshow.show);
19:     p.appendChild(slideshow.next);
20:     o.parentNode.insertBefore(p, o);
21: },

  • 第2和3行,刚开始创建一个 P 元素,用来包含整个幻灯片导航,并应用一个名为 slidenav 的 class。
  • 第4和5行,创建一个新的链接元素,储存在叫 prev 的属性中,设置 href 属性为 #。使链接显示为一个真正的链接且键盘可用,是有必要的。
  • 第6行,创建一个新的文本标签。
  • 第7行,将文本标签添加到链接上。
  • 第8行,添加一个事件处理函数,指向 show() 监听方法。
  • 第9行,将新的链接添加到 段落上。
  • 第10行,开始计数器,我们创建一个 SPAN 元素,并用 count 属性储存他。
  • 第11行,创建一个新的文本节点,显示当前幻灯片在总数中的位置。我们需要给当前的属性增加 1,因为人类计数是从 1 开始而非从 0。
  • 第12行,将文本作为新的子节点,添加至 SPAN 上 。
  • 第13行,将 SPAN 元素 添加到段落上。
  • 第14至19行,基本上是复制 4 到 9 行,这次重新创建链接唯一不同的是文本标签,他储存在 next 属性上。
  • 第20行,将最近创建的段落插入到文档中初始的图片列表前。



这些被创建的所有标记都是必要的,最后剩下的是去定义一个当链接被点击时调用的监听方法 show() 。

复制内容到剪贴板
代码:
1: show:function(e){
2:     if(this === slideshow.next || this === slideshow.prev){
3:         slideshow.removeClass(slideshow.items[slideshow.current], 'current');
4:         var addto = (this === slideshow.next) ? 1 : -1;
5:         slideshow.current = slideshow.current + addto;
6:         if(slideshow.current < 0){
7:             slideshow.current = (slideshow.all-1);
8:         }
9:         if(slideshow.current > slideshow.all-1){
10:             slideshow.current = 0;
11:         }
12:     }
13:     var templabel = document.createTextNode((slideshow.current+1) + ' / ' + slideshow.all);
14:     slideshow.count.replaceChild(templabel, slideshow.count.firstChild);
15:     slideshow.addClass(slideshow.items[slideshow.current], ‘current’);
16:     slideshow.cancelClick(e);
17: },

  • 第1行,得到作为参数 e 的当前事件对象,这是稍后调用的 cancelClick() 唯一需要。
  • 第2行,检测点击的元素是否是向下或者向前链接(this 由 addEvent() 返回)。
  • 第3行,从当前显示的幻灯片上移除 current 的 class。由于现在有一个被点击的链接,这将成为可能。
  • 第4行,通过比较 this 和 next 属性,决定 current 的计数器是应该增加还是减少。
  • 第5行,修正计数器。
  • 第6到11行,确定计数器将永远不会超出范围,当你在第一幻灯片并点击了向前的链接,将设置他为最后一个,而当你在最后一个幻灯片,点击了向后的链接,将设置为第一个。
  • 第13和14行,生成一个新的计数器文本并替代旧的。
  • 第15行,通过设置名为 current 的 class,显示新的当前幻灯片。
  • 第16行,通过调用 cancelClick() 阻止链接的默认行为。



这些是脚本的所有内容。现在这个脚本可以工作,但仍不是真正可维护的。

第五步:轻松维护(Easing Maintenance)

脚本功能齐全,分离式而且无懈可击。真正的问题是,现在并不方便维护。

脚本应用的最大的问题大概是,并不是所有的维护者都懂 JavaScript 和愿意在你的脚本中寻找需要修改的部分。

为了避免维护者做这些,最安全的方法就是把脚本和 CSS 中使用的命名和 ID 从你的脚本功能中分离出来。此外,从使用的脚本中分离出文本标签也是个好点子,因为他们可能会改变。例如,当脚本使用其他语言本地化时。

工具方法的复用

第一件要做的事情就是,从主要脚本中分离出其他脚本也可以再用的工具函数。这也许是大部分 JavaScript 库的开始。

tools.js:

复制内容到剪贴板
代码:
/* 辅助方法 */
tools = {
    addEvent:function( obj, type, fn ) {
        if ( obj.attachEvent ) {
            obj['e'+type+fn] = fn;
            obj[type+fn] = function(){
                obj['e'+type+fn]( window.event );
            }
            obj.attachEvent( 'on'+type, obj[type+fn] );
        } else
            obj.addEventListener( type, fn, false );
        },
    removeClass:function(o,c){
        var rep=o.className.match(' '+c)?' '+c:c;
        o.className=o.className.replace(rep,”);
    },
    addClass:function(o,c){
        var test = new RegExp("(^|\\s)" + c + "(\\s|$)").test(o.className);
        if(!test){o.className+=o.className?' '+c:c;}
    },
    cancelClick:function(e){
        if (window.event){
            window.event.cancelBubble = true;
            window.event.returnValue = false;
        }
        if (e && e.stopPropagation && e.preventDefault){
            e.stopPropagation();
            e.preventDefault();
        }
    }
}

CSS 的 class 和 ID —— 外观

下一步要做的是,分离外观的 class 和 ID 到一个单独的包含文件。保证他们在 slideshow 命名空间里是安全的,因为其他脚本不太可能用到他们。也不会妨碍写一个简短的说明注释。

slideshow-css.js:

复制内容到剪贴板
代码:
slideshow.css = {
    /*
    这些都是幻灯片效果中使用到的 classe 和 ID。
    你可以在这里修改他们中的任何一个。
    务必请使用引号包围名称,用逗号结尾(除了最后一个)。
    */
    showID               :'slideshow',
    dynamicClass         :'js',
    slideNavigationClass :'slidenav',
    currentClass         :'current'
}

文本标签(Text labels)—— 解释给终端用户

最后但不是最不重要的,让我们将文本标签放到一个单独的包含文件,再次使用 slideshow 命名空间。

slideshow-labels.js:

复制内容到剪贴板
代码:
slideshow.labels = {
    /*
    这些都是幻灯片效果中使用到文本标签。
    你可以在这里修改他们中的任何一个。
    务必请使用引号包围名称。
    最后一个结尾不用逗号。
    */
    previous       : '<<',
    next           : '>>',
    counterDivider : ' of '
}

改变的主要脚本

然后,我们需要修改主要脚本使用此信息,而不是依赖嵌入式的数据。没有太多的改变,很容易用搜索加替换就能做到。

slideshow.js:

复制内容到剪贴板
代码:
slideshow = {
    current:0,
    init:function(){
        if(document.getElementById && document.createTextNode){
            var list =document.getElementById(slideshow.css.showID);
            if(list){
                slideshow.items = list.getElementsByTagName('li');
                slideshow.all = slideshow.items.length;
                if(slideshow.all > 1){
                    tools.addClass(list, slideshow.css.dynamicClass);
                    slideshow.createNav(list);
                }
            }
            slideshow.show();
        }
     },
    createNav:function(o){
        var p = document.createElement('p');
        tools.addClass(p, slideshow.css.slideNavigationClass);
        slideshow.prev = document.createElement('a');
        slideshow.prev.setAttribute('href', '#');
        var templabel = document.createTextNode(slideshow.labels.previous);
        slideshow.prev.appendChild(templabel);
        tools.addEvent(slideshow.prev, 'click', slideshow.show);
        p.appendChild(slideshow.prev);
        slideshow.count = document.createElement('span');
        templabel =document.createTextNode((slideshow.current+1) + slideshow.labels.counterDivider + slideshow.all);
        slideshow.count.appendChild(templabel);
        p.appendChild(slideshow.count);
        slideshow.next = document.createElement('a');
        slideshow.next.setAttribute('href', '#');
        var templabel = document.createTextNode(
        slideshow.labels.next);
        slideshow.next.appendChild(templabel);
        tools.addEvent(slideshow.next, 'click', slideshow.show);
        p.appendChild(slideshow.next);
        o.parentNode.insertBefore(p, o);
    },
    show:function(e){
        if(this === slideshow.next || this === slideshow.prev){
            tools.removeClass(slideshow.items[slideshow.current],
            slideshow.css.currentClass);
            var addto = this === slideshow.next ? 1 : -1;
            slideshow.current = slideshow.current + addto;
            if(slideshow.current < 0){
                slideshow.current = (slideshow.all-1);
            }
            if(slideshow.current > slideshow.all-1){
                slideshow.current = 0;
            }
        }
        var templabel = document.createTextNode((slideshow.current+1) + slideshow.labels.counterDivider + slideshow.all);
        slideshow.count.replaceChild(templabel, slideshow.count.firstChild);
        tools.addClass(slideshow.items[slideshow.current], slideshow.css.currentClass);
        tools.cancelClick(e);
    }
}
tools.addEvent(window,'load',slideshow.init);
视频教程列表
文章教程搜索
 
Javascript推荐教程
Javascript热门教程
看全部视频教程
购买方式/价格
购买视频教程: 咨询客服
tel:15972130058