JavaScript高级编程

         原文地址: http://www.onlamp.com/pub/a/onlamp/2007/07/05/writing-advanced-javascript.html

        Web应用程序(Web Applications)
        从计算机纪元的黎明刚刚来临开始,不同平台间软件的互用性就一直是关注的焦点。为了尽可能实现用户的最大要求,软件发布者往往将流行软件从一个机器移植到另外一个机器上,这通常要花费数月的辛苦劳动,有时甚至是整个软件在新的硬件或者操作系统上的完全重写。随着计算机功能的不断强大,像C/C++这样的语言成为在多种平台上可用的标准,这是更加容易实现,一个程序只编写一次,就可以在所期望的众多系统上编译。只要系统中包含C编译器,软件就可以构建,并且可能会按照预期运行。
        然而,当使用图形用户界面(GUI)的软件成为标准化时,就有了另外一个问题。Macs上的GUI和Windows或者Unix上的各种效果大相径庭。当然,有一些所谓的“widget toolkit”,像Tcl/Tk或者wxWidgets,可以绑定到很多流行的语言,如C++、Python和Perl。开发人员使用这些小工具可以创建平台无关的GUI,它们可以在Windows、Linux、Mac OS X和其他操作系统表现出(几乎)同样的动作。不过,在今天,几乎所有的机器上都有一个功能尤为强大的GUI解释器:web浏览器(the web browser)。
        web浏览器 虽然最初只是为了以一种相对令人舒服的方式显示标记文本,但是今天已经发展到另外一个顶点。它们可以作为令人惊奇的复杂的软件界面,可以媲美那些使用C/C++和其他高级语言编写的软件。这些大部分要归功于JavaScript支持和Web2.0技术。几乎每一个平台上的每一个浏览器都支持该脚本语言的一个通用子集,这使得编写平台无关程序变得更加容易。
         JavaScript工具箱(JavaScipt Toolkits)
         最近,出现了很多来自于像YahooGoogleDojo等地方的免费的JavaScript工具箱。非常像上面提到的widget toolkits,它们提供了各种各样使用JavaScript编写的小工具,如菜单、日历或者树,并且开发人员可以将它们轻而易举地继承到自己的网站或者web程序中。这里有一个不错的小总结。
        如果需要为网页增加一些特效,这些工具是非常不错的,也有很多优点。它们已经在很多浏览器上进行过测试,可以在运行在所有标准的浏览器上。其中一些工具还包含了良好的文档,它们使得实现一个奇幻的网页变得轻而易举。然而,它们也可能是非常臃肿的,会为你的网页再增加数百KB,有时你又不得不等待对新浏览器支持功能的添加(例如,其中一些还不能在IE7上运行)。另外,很多公司不会或者不愿意使用开源软件,主要是因为软件责任的缺失(也就是,你必须自己承担使用它的风险),并且在调试方面也有很多困难。
       本系列文章计划作为高级JavaScript技术指南,演示如何创建多浏览器兼容widget(包含完整的代码),类似前面提到的那些小工具,另外也会详细解释它们的工作原理。诸如实现如菜单、tab或树等之类的例子在网上随处可见,但是很多要么是代码编写得极其蹩脚,要么不具备跨浏览器兼容性。关于JavaScript、CSS、DOM和HTML有一个比较好的参考网站是www.w3school.com,如果在本文讨论的示例中遇到不熟悉的JavaScript函数或者HTML/CSS标签建议参考此网站。该网站上还有一篇关于HTML DOM的指南。将要讨论的内容有弹出式菜单、浮动消息、拖拽对象和XML HTTP(在不重载页面的情况下动态更新页面内容)。
        应该指出的是,讨论的函数都已经在Windows XP下IE7和FIrefox2.0上测试通过,但是它们应该可以在当前流行的所有浏览器上运行。任何浏览器相关的代码都在讨论过程中特别指出。另外,请紧记,使用JavaScipt和DOM有很多方法可以实现同样的目的。下面的例子只是给出了一种这样的方法,在所有方式中并不是必要的最快的或者最好的。所有的例子都依据简单、实现功能并且依据阅读的原则编写。
        JavaScript的魔力(The Magic of JavaScript)
        我们将要看到的第一个例子是如何显示一个浮动的文本(或图片),并且在拖动浏览器窗口的滚动条时仍然会停留在同一个地方。这可以用来在web程序向用户显示一个消息,如“Please wait”,或者在网页增加一个水印。只需要几行JavaScript代码就可以实现这个效果:      

 
        
       使用下面的两个JavaScript函数可以完成上面的功能:

var ie = document.all;
var moz = document.getElementById && !document.all; 
var intr;

function Message_UpdatePos(msg, dy) ...{
    var el = document.getElementById(msg);
    if (ie) ...{
        el.style.pixelTop = document.body.scrollTop + dy;
    }
    else if (moz) ...{
        el.style.top = window.pageYOffset + dy + 'px';
    }
}

function Message_Display(msg, vis, dx, dy) ...{
    var el = document.getElementById(msg);

    // Position Message

    if (ie) ...{
        el.style.pixelTop = document.body.scrollTop + dy;
        el.style.pixelLeft = document.body.clientWidth - dx;
    }
    else if (moz) ...{
        el.style.top = window.pageYOffset + dy + 'px';
        el.style.left = window.innerWidth - dx + 'px';
    }
    if (vis) ...{  // and display it
        el.style.visibility = "visible";
        intr = setInterval("Message_UpdatePos('" + msg + "', " + dy + ")", 1);
    }
    else ...{  // or hide it
        el.style.visibility = "hidden";
        if (intr)
            clearInterval(intr);
    }
}

          消息本身可以在页面上允许使用span标签的任何位置初始化:

<span id="testmsg" style="position: absolute;
visibility: hidden; background: red;">This is a test…</span>

          按钮的实现代码分别是:

onclick="Message_Display('testmsg', 1, 700, 50); return false;"

          显示消息,以及

onclick="Message_Display('testmsg', 0, 700, 50); return false;"

          隐藏消息。
        Message_Display的参数是:包含消息文本的span标签的id、一个表示显示或者隐藏消息的布尔值,以及消息的显示位置——相对于浏览器窗口右上角的x和y偏移量(在本例中是距离右端700px,顶端50px)。这里的关键所在span标签的style。通过使用绝对定位,我们是消息浮动在页面上,而不是附在页面随着页面滚动而滚动。我们还应该简要地说明一下为什么使用span标签。span和div标签本质都是“什么事情都不干(do nothing)”的标签,在文档中分别被用来描绘水平和垂直的块。正常情况下,它们在页面上都是不可见的,所以可以用来通过特定的样式来包围一块内容,而不用改变整个页面。因此在创建JavaScript小工具,它们是十分方便的。
        这个函数的工作流程如下。首先,通过getElementById(获得标签指针的最简单方法)获得消息span标签的句柄。接下来,区分Internet Explorer(ie)或Firefox/Mozilla(moz),但是都要实现同样的目的——将消息定位到期望的位置(dx,dy)。使用visibility样式控制消息的显示和隐藏。最后一行需要更进一步的解释JavaScript的定时器(Timer)。
        定时器是JavaScript中在某段时间后执行一个函数的有效方式,既可以使用setTimeout只执行一次,也可以使用setInterval循环执行。这些函数是非常有用的,因为在JavaScript中没有和sleep等价的命令,所有它们就提供了最好的替代方式。直到指定的时间过去,否则它们是消耗CPU时间的。开发人员必须注意不能滥用这些强大的工具,但是只要适当使用就会产生令人印象深刻的效果。在本例中,我们根据参数vis设置定时器执行Message_UpdatePos(msg, dy)。若vis非零,则定时器设置为每1毫秒执行一次。注意,我们必须定时器指针保存在全局变量intr中,因为在多次调用Message_Display时它要一直存在。
        最后来看Message_UpdatePos,注意本质上它和Message_Display的开头部分完成同样的工作,获得消息句柄和更新到页面顶端的y偏移量。因此,当页面滚动时,消息的位置就会滚动事件完成1ms重新调整,看起来它好像一直漂浮在右上角的同样位置。注意,如果浏览器在水平方向调整大小(变宽或者变窄),消息并不会移动。作为,看你是否可以修改代码使其在该种情况也改变位置。
        弹出式菜单(Pop_up Menus)
        接下来,也是本文讨论的最后一个小工具,它比上一个例子更加复杂:弹出式菜单。
        首先,看一下运行的结果:

Menu Item #1
Menu Item #2
Menu Item #3

For menu click here: X

        这个例子更加复杂是因为它包含了一个JavaScript函数和一些更加复杂的事件处理。下面是用到的JavaScript代码和HTML:       

function getElementAbsPosX(el)
...{
    var dx = 0;
    if (el.offsetParent) ...{
        dx = el.offsetLeft + 8;
        while (el = el.offsetParent) ...{
            dx += el.offsetLeft;
        }
    }
    return dx;
}

function getElementAbsPosY(el)
...{
    var dy = 0;
    if (el.offsetParent) ...{
        dy = el.offsetTop + el.offsetHeight / 2;
        while (el = el.offsetParent) ...{
            dy += el.offsetTop;
        }
    }
    return dy;
}

function GetAbsWindowBottom()
...{
    // Compute the bottom of the popup window and the bottom of
    // the browser window, in absolute co-ordinates - different
    // on all browsers but the below should be accurate usually!
 
    var abswindowbottom = 0;
    if (typeof(window.innerHeight) == 'number')
        abswindowbottom = window.innerHeight;
    else if (document.documentElement && document.documentElement.clientHeight)
        abswindowbottom = document.documentElement.clientHeight;
    else if (document.body && document.body.clientHeight)
        abswindowbottom = document.body.clientHeight;
 
    if (typeof(window.pageYOffset) == 'number')
        abswindowbottom = abswindowbottom + window.pageYOffset;
    else if (document.body && document.body.scrollTop)
        abswindowbottom = abswindowbottom + document.body.scrollTop;
    else if (document.documentElement && document.documentElement.scrollTop)
        abswindowbottom = abswindowbottom + document.documentElement.scrollTop;
    return abswindowbottom;
}

function PopupMenu(name, vis)
...{
    var el = name + 'menu';
    var tag = name + 'menuroot';
    if (!document.getElementById(el))  // menu object not found
        return;
    if (vis == 0) ...{  // hide the menu
        document.getElementById(el).style.visibility = 'hidden';
        return;
    }

    // Get menuroot position
    var pos = document.getElementById(tag);
    var dx = getElementAbsPosX(pos);
    var dy = getElementAbsPosY(pos);

    // Compare bottom of menu to bottom of window
    var abspopupbottom = dy + document.getElementById(el).clientHeight + 10;
    var abswindowbottom = GetAbsWindowBottom();

    // If menu goes below bottom of window, move it up!
    if (abspopupbottom > abswindowbottom)
        dy = dy - (abspopupbottom - abswindowbottom);

    // Set final menu position and make it appear
    document.getElementById(el).style.left = dx + 'px';
    document.getElementById(el).style.top = dy + 'px';
    if (vis > 0)
        document.getElementById(el).style.visibility = 'visible';
}

        实现菜单的HTML代码,和前面例子中的span一样,可以放在页面中任何允许div标签的位置:

<div id="testmenu" style="position: absolute; visibility: hidden; color: #aaaaaa; font-style: italic; border: solid thin #888;
 background-color: #afafaf; padding: 4px;" onmouseover="clearTimeout(tout);" onmouseout="tout=setTimeout('PopupMenu('test', 0);', 1500);">
 <table>
  <tr>
   <td><span style="cursor:pointer; color:blue;" onclick="PopupMenu('test', 0);">Menu Item #1</span></td>
  </tr>
  <tr>
   <td><span style="cursor:pointer; color:blue;" onclick="PopupMenu('test', 0);">Menu Item #2</span></td>
  </tr>
  <tr>
   <td><span style="cursor:pointer; color:blue;" onclick="PopupMenu('test', 0);">Menu Item #3</span></td>
  </tr>
 </table>
</div>

        增加菜单的初始化代码:

<span id="testmenuroot" style="cursor:pointer; color:blue;" 
onclick="PopupMenu('test', 1); tout=setTimeout('PopupMenu
('test', 0);', 1500);" >X</span>

        首先,我们来看一下菜单。我们可以在div标签中放置任何我们喜欢的东西,所有的秘密都在div标签的属性中。特别需要注意的,和前面的例子一样,我们使用绝对定位,所以不管其他文本和图片出现的位置,我们都可以控制菜单的确切位置。我们还要确保菜单开始时visiblity:hidden,并且分配了ID testmenu,这样我们就可以在后面很容易获得一个句柄。
        在div标签中,我们还会遇到setTimeout和clearTimeout函数的第一次使用。它们和上例中的setInterval函数的行为类似,只不过它们在某段时间后只执行一个命令一次。在本例中,它们用来在鼠标移出菜单区域1500毫秒后关闭菜单,或者鼠标重新移回到菜单区域时(如果仍然处于打开状态)取消退出效果。tout是在JavaScript文件中定义的一个全局变量,用来保存定时器对象的指针。当触发onmouseout事件时(鼠标移动由div标签指定的菜单区域之外)PopMenu('test', 0)被设定为在1500毫秒后调用(注意我们是如何转移引号的,因为它们已经在引号之内)。假如在1500毫秒耗尽之前动作没有被取消,这个函数就会被调用,菜单就会消失(就像我们在下面将要看到的那样)。然后,如果onmouseover时间被触发(鼠标移动到菜单上),clearTimeout(tout)就会执行,它会阻止取消定时器,阻止菜单消失,直到用户触发下一次鼠标事件。
        在菜单自身内部,我们会包含一些执行其他任务或跳转其他页面的链接。当然,本例中只是一些虚假的链接。然而,注意每一个菜单项的onclick事件。在div标签上面,一点击菜单项菜单就会消失(试一下!)。注意,这里没有使用timeout,因为我们想在这种情况下菜单立即消失。
        接下来是由id为testmenuroot的span标签包含的一段HTML代码,表示了菜单实际出现的点击区域。在本例总,我们只是在span标签中间放置了一个X字母,当然,你可以在这里放你喜欢的任何东西:按钮、图片等等。需要注意的另外一个事情是onclick时间,它使菜单显示,并且设置定时器以在1500ms后关闭菜单。然而,我们已经只要用户移动鼠标到菜单区域,定时器就会被取消,并且菜单会一直显示,直到下次鼠标移走。
        最后,我们来看JavaScript函数本身,PopupMenu。它依赖的函数有:GetAbsWindowBottom,获得浏览器底部的绝对位置;getElementAbsPosX和getElementAbsPoxY,获得一个元素在绝对坐标系中的x和y位置。最后两个的计算方式是通过迭代加上父元素的偏移量,直到DocumentRoot。这些函数看起来有些过于复杂了,但是它们极有可能是在几乎每一个流行的浏览器上获得这些信息的唯一方式。不幸的是,每一个浏览器都使用一个非常不同的方式保存这些信息。
        PopupMenu函数有两个输入参数:name和一个表示菜单应该显示或隐藏的标志。关于name,假设菜单被一个标签包围形成,其id由name参数加上“menu”组成(那么在我们的例子中就是“testmenu”,因为参数为“test”)。类似地,假设菜单的左上角定位在id为name加“menuroot”的标签(本例中为“testmenuroot”)上。如果vis参数是0,我们只需要把菜单标签的visibility的样式设置为hidden。否则,我们需要使菜单出现在右侧的位置上。首先,我们使用GetElementAbsPos函数获得“menuroot”标签的绝对位置。然后,我们可以把菜单的位置设置为这些值,这就可以让菜单的左上角出现在我们点击以使其弹出的位置。然而,我们还不希望菜单滚动出页面的底端,因为这是非常令人讨厌的。注意多数包含弹出式菜单的widget toolkits都只实现上面的功能,所以我们将尝试实现一个更好的。我们可以计算出绝对坐标系中窗口以及弹出菜单的底部位置,接下来的两行代码完成了这个任务。注意,菜单的高度由clientHeight属性给出,我们再加上10以使和页面底部留下一些空间。然后我们可以检查弹出菜单是否已经向下超出了浏览器窗口的底部,如果是这样,就会相应地调整它的坐标,如此它的底部就会刚刚接触窗口的底部。最后,我们接着向下看,就是定位弹出式菜单,并使其可见。
        总结(Summary)
        但愿,这次讨论和这两个例子可以让你领略到使用仅仅几行JavaScript代码就可以完成的事情,并且揭示了在JavaScript工具内部并没有很多很多的魔法。尽管有时候有些棘手,但是通常只需要额外的一点工作来确保函数可以在所有的主流浏览器上运行,并且这些小小的额外付出几乎永远是值得的。在后面的文章中,将会讨论更加详细的JavaScript widget的示例。
      
        Howard Feldman是在位于Montreal, Quebec的Chemical Computing Group一名研究科学家。
      

时间: 2024-10-09 03:39:10

JavaScript高级编程的相关文章

《JavaScript高级编程》学习笔记之object和array引用类型_javascript技巧

本文给大家分享我的javascript高级编程学习笔记之object和array引用类型,涉及到javascript引用类型相关知识,大家一起看看把. 1. Object类型      大多数引用类型值都是Object类型的实例:而且Object也是ECMAScript中使用最多的一个类型.      创建Object实例有如下两种方式: new操作符后跟Object构造函数: var person=new Object( ); person.name="webb"; person.a

JavaScript高级编程 III

    原文地址:http://www.onlamp.com/pub/a/onlamp/2007/11/20/advanced-javascript-iii.html     JavaScript高级编程I:http://blog.csdn.net/mydeman/archive/2007/08/20/1751479.aspx    JavaScript高级编程II:http://blog.csdn.net/mydeman/archive/2007/08/23/1755760.aspx     

javascript高级编程之函数表达式 递归和闭包函数_javascript技巧

定义函数表达式有两种方式:函数声明和函数表达式. 函数声明如下: function functionName(arg0,arg1,arg2){ //函数体 } 首先是function关键字,然后是函数的名字. FF,Safrai,Chrome和Opera都给函数定义了一个非标准的name属性,通过这个属性可以访问到函数指定的名字.这个函数的值永远等于跟在function关键字后面的标识符. //只在FF,Safari,Chrome和Opera有效 alert(functionName.name)

JavaScript高级编程II

     原文地址: http://www.onlamp.com/pub/a/onlamp/2007/08/23/advanced-javascript-ii.html?page=1         在前面的文章中,我们介绍了两类JavaScript小工具及其源码:浮动文本和弹出菜单.本文中,我们将继续介绍另外几个有用的JavaScript小工具,并着重说明其工作原理,因此你可以简单修改后应用到自己的程序中.本文中的JavaScript代码应该不用做任何修改就可以在当前所有主流浏览器上运行.所以

Javascript函数式编程简单介绍_javascript技巧

几十年来,函数式编程一直是计算机科学狂热者的至爱,由于数学的纯洁性和谜一般的本质, 它被埋藏在计算机实验室,只有数据学家和有希望获得博士学位的人士使用.但是现在,它正经历一场复兴, 这要感谢一些现代语言比如Python,Julia,Ruby,Clojure以及--但不是最后一个--Javascript. 你是说Javascript?这个WEB脚本语言?没错! Javascript已经被证明是一项长期以来都没有消失的重要的技术.这主要是由于它扩展的一些框架和库而使其具有重生的能力, 比如backb

JavaScript Ajax编程 应用篇_javascript技巧

一.Ajax  (Asynchronous JavaScript + XML)  能够像服务器请求额外的数据而无需卸载页面,即局部刷新技术二.创建一个XHR对象 function createXHR () { if (typeof XMLHttpRequest != "undefined") { return new XMLHttpRequest(); } else if (typeof ActiveXObject != "undefined") { // <

详解Javascript事件驱动编程_javascript技巧

一.基本概述     JS是采用事件驱动的机制来响应用户操作的,也就是说当用户对某个html元素进行操作的时候,会产生一个时间,该时间会驱动某些函数来处理. PS:这种方式和Java GUI中的事件监听机制很像,都是需要注册监听,然后再处理监听,只不过实现的方式不同而已. 二.事件驱动原理 事件源:产生事件的地方(html元素) 事件:点击/鼠标操作/键盘操作等等 事件对象:当某个事件发生时,可能会产生一个事件对象,该时间对象会封装好该时间的信息,传递给事件处理程序 事件处理程序:响应用户事件的

JavaScript高级应用:例外处理

javascript|高级 程序开发中,编程人员经常要面对的是如何编写代码来响应错误事件的发生,即例外处理(exception handlers).如果例外处理代码设计得周全,那么最终呈现给用户的就将是一个友好的界面.否则,就会让访问者对莫名的现象感到真正的"意外".本文就将为你介绍Web开发中JavaScript语言的例外处理技术. 一.什么是例外处理 当JavaScript程序在运行中发生了诸如数组索引越界.类型不匹配或者语法错误时,JavaScript解释器就会引发例外处理.EC

Javascript高级应用:文件操作篇

javascript|高级 Javascript是网页制作中离不开的脚本语言,依靠它,一个网页的内容才生动活泼.富有朝气.但也许你还没有发现并应用它的一些更高级的功能吧?比如,对文件和文件夹进行读.写和删除,就象在VB.VC等高级语言中经常做的工作一样.怎么样,你是否需要了解这方面的知识?那就请跟我来,本文将详细描述如何使用Javascript语言进行文件操作. 一.功能实现核心:FileSystemObject 对象 其实,要在Javascript中实现文件操作功能,主要就是依靠FileSys