JavaScript基本对象

| |
[不指定 2005/03/16 22:29 | by ipaddr ]
原文地址:http://www-900.ibm.com/developerWorks/cn/lotus/lo-jsobj/index.shtml

亲密接触单选按钮、复选框和JavaScript的一些有趣的事情



我将以对象模型和一些常用对象开始,因为JavaScript里的一切都是从对象展开的。记住,本文不只是关于JavaScript的,它是关于Notes/Domino中的JavaScript的。


亲密接触单选按钮、复选框和JavaScript的一些有趣的事情
我将以对象模型和一些常用对象开始,因为JavaScript里的一切都是从对象展开的。记住,本文不只是关于JavaScript的,它是关于Notes/Domino中的JavaScript的。
窗口
窗口是对象模型的顶端对象。通常来说,窗口就是你的浏览器。如果你的窗口里有帧结构,那么每个帧结构都依次是一个小窗口,包含在顶层窗口——浏览器中。我会在另一篇文章里谈帧结构,现在,我们来看浏览器里只有一个Web页面的情况。

窗口有它的属性,比如它的地址(也就是它的URL),浏览器底部的状态条上的文字等等;它也有方法,比如打开和关闭。通常来说,因为窗口在对象层次的顶层,JavaScript就假设Window已经存在了,你不必去刻意写上它,也就是说"window.location"和"location"的作用是相同的。

窗口里是Web页面,它的对象层次从文档(document)开始。你可以用Window.document来引用它,或者就是简单的document。每个窗口只有一个文档(document)。依据你的浏览器的不同,文档(document)有几个变化多样的选项。在MSIE中,document.all数组包含了文档(document)中所有的对象。在Netscape Navigator的某些版本中,你可以访问document.layers数组。每一种浏览器关于对象的解释都不一样,但是表单数组(forms array)在所有的浏览器中都是可以访问的。

理论上讲,每个文档(document)包含至少一个表单(form),但是可以包含多个。然而,在Notes中,除非明确写出用来完成特定功能的HTML代码(我从来没那么做过),通常只有一个表单。但是,因为可以有多个表单,所以你在引用表单时,还是得通过数组元素来引用表单,下标从0开始。不像LotusScript那样,用圆括号来括住下标数字,比如doc.CompanyName(0),在JavaScript中你通常会看到引用数组下标的数字是括在方括号中的。因此,你应该用下面的方式引用表单:

window.document.forms[0];




或者简写成:

document.forms[0];




严格来说,上面的方法并不是唯一引用表单的方式,下面都是引用表单的合法的表达式:

document.forms[0];
document.forms(0);
document.forms.0;




然而,你经常看到的还是带方括号的方式。注意,我在每行语句的末尾加了分号,这是在JavaScript中和公式语言的相似之处之一。你应该在每一条语句的末尾加上分号。和公式语言不同的是,在JavaScript中分号并不总是必需的。有些浏览器和其他浏览器比起来,它们可以运行没有分号的JavaScript语句,所以,尽管有时你可以不用加分号,但是你最好养成每一条语句都加分号的习惯。

当你接触到表单后,你就已经为访问你最关心的元素做好了准备。表单是域、按钮、文本、图像和其他元素的容器,你将在表单中用JavaScript来处理这些元素。

简单的几个元素
对于LotusScript,有件事值得一提:除了Rich-Text域外的元素,如文本、单选框、列表框、复选框等,你可以用几乎相同的代码取得它们的值。例如:如果有一个"Location"域,不论它是何种类型,你都可以用下面的LotusScript代码取得它的值:

fieldVals = doc.Location




或者这样:

fieldVals = doc.GetItemValue("Location")




在LotusScript中,域的类型对于你要取值(值数组)的代码并不重要。不幸的是,这对于JavaScript并不适用。在JavaScript中,不同类型的域除了显示选项(比如单选框、复选框或者文本)外,并不像在Notes里那样,它们是不同的类型的对象,每一个都要用不同的方式去引用。其实,那也不是绝对的,有些对象是相似的,但是引用过程并不像在LotusScript里那么流畅。你会发现,你将花费很多时间手动寻找你的代码中的域(名)错误来使它们正常运行,那看起来很糟糕。

你首先要知道的一点是:在JavaScript中,没有所谓的Rich-Text域,在HTML中更没有。Notes里提供了一个可以放在浏览器里的富文本Java(不是JavaScript)小程序,从而可以得到富文本的一些功能,但是你并不能用JavaScript来对它编程,而且它也不是一个真正的HTML对象类型。

更让Notes开发人员惊讶的是,在Web上还没有数字型或时间型的域。HTML的域都是文本型的。尽管你能用它们来收集数字信息,如数量或单价,而保存的数据依然是文本。为了像数字一样使用它,你必须把它转换成数字类型。我将在后面详细讲解它。现在,要意识到一切都是文本,就像你在Notes的@Prompt对话框里输入的信息一样。



图 1

建立表单
为了理解得更深入,你将在我的帮助下做一个小实验。打开Domino Designer,创建一个新表单,在表单上创建一个名为"Get editable field value"的按钮和一个名为"CreatedBy"的文本域,把此域的缺省值设成:@V3UserName(如图1)。

如果你用R5的设计器(Designer),请把触发按钮的语言改成JavaScript。如果你像我一样用R6的设计器(Designer),就要稍微麻烦一些。在Notes/Domino6(ND6)中,你可以像在浏览器中使用JavaScript一样在Notes客户端中使用JavaScript。更重要的是,同一个按钮在不同的客户端里能运行不同的代码。在图2中,你将会看到一些选项,你将决定所写的代码是在Notes("客户端")还是在浏览器("Web")里运行。



图 2



图 3

这个功能当你在不同的环境里运行不同的代码时非常有用,但是当你要在两种环境里运行同样的代码时怎么办呢?当然有比拷贝按钮代码更好的方法,你可以在右边的下拉列表中选择最下面的Common JavaScript来为两种环境同时编写代码(如图3)。

在本例中,选择"Common JavaScript"。

在按钮脚本中,输入提示用户CreatedBy域值的代码。如果你看过前一篇文章,你就知道可以用点来分隔JavaScript里的各个层级元素。你的按钮脚本应该如下所示:

alert(document.forms[0].CreatedBy.value);




需要注意的是,JavaScript区分大小写。这个规则不只对JavaScript元素(文档、表单等)有效(首字母小写),对域的名字同样有效。你在域中用的什么大小写效果,在代码中必须如实反映。在浏览器中试验一下按钮的功能[Design>Preview in Web Browser>Internet Explorer(或者你自己的浏览器)]。如果你使用Domino R6的设计器(Designer),你可以在Notes客户端中进行试验(Design>Preview in Notes)。



图 4

如果你在用一个本地数据库进行试验(对应的是在服务器上),在浏览器中你看到的用户名将是"Anonymous",而不是你的名字,然而在Notes客户端中却是你的名字。原因是当你用Web页面的方式访问本地数据库时,你没有登录到服务器,浏览器不知道你是谁。但是在Notes中,不论是本地还是服务器,你必须登录才能使用系统。这就是两种客户端之间微妙的差别。

另一个区别是在Web上没有计算域,但并不意味着你不能在你的表单里加入计算域。你可以加入计算域,计算值将会在Web页中显示,除非域是隐藏的。关键是即使域就在那里显示,而HTML通常的处理是没有定义域。如果你把CreatedBy域改成计算域而不是可编辑的,在重新测试时你就会明白我所说的意思,你会得到和图4类似的提示信息。

但是当你在Notes客户端(R6)里运行时,即使是计算域也没有任何错误。坦白地说,我还没有对这个功能是好还是坏下结论,但那就是我们所得到的结果。

这里产生的错误非常重要,你要开始理解JavaScript里产生的错误,因为它对你的代码调试有很大的用处。那么当它提示你"document.forms.0.CreatedBy.value"为null值或不是对象时,意味着没有得到你想要的数据。

当你返回到浏览器里,在背景上单击右键,选择"查看源文件"时,你会看到隐藏在Web页面下的HTML代码。你简单浏览代码时,会看到对按钮和计算域的引用,如下所示:

<input type="button" onclick="alert(document.forms[0].CreatedBy.value);" value="Get editable field value">
<p>Created By:Anonymous




当你对页面进行过排版的话,你的代码里可能会有字体、段落或其他的标记混杂在按钮和计算域的代码里。那些是格式化文档用的,在此处的讨论中可以略过不看。注意看"Anonymous"是表单上的另一个单词,它没有任何的标记在两旁来提示你它是从域产生的。在源代码中,Anonymous和"Created By"没有任何区别:两个在域前面的静态文本(如果你已经登录,你将看到你的名字而不是Anonymous)。

为了比较一下,把CreatedBy域改回可编辑文本,保存表单,回到浏览器并刷新页面,再看页面的源文件,将会如下所示:

<input type="button" onclick="alert(document.forms[0].CreatedBy.value);" value="Get editable field value">
<p>Created by:<input name="CreatedBy" value="Anonymous">




代替单词Anonymous(或是你的名字)的是域的HTML代码(或者严格地讲,是HTML的文本输入框)。它的名字是"CreatedBy",值是"Anonymous"。这些是通过JavaScript能取得的属性,而普通的文本却没有这些属性。所以你不能用JavaScript来引用计算域,至少在浏览器中如此。还有一点令人迷惑的就是当文档在非编辑状态下时,即使是可编辑域,也不能用JavaScript来引用它。换句话说,当你保存了文档再次打开,但没有把它设置成编辑模式时,页面的HTML代码将和CreatedBy域是计算域时相同。另外一个关于JavaScript的有趣的现象是:在Domino以外,我们没有太多的机会去处理表单的编辑和非编辑状态,而对于我们Domino开发者来说,这可是个大问题。

你注意到按钮和域都转换成输入对象了吗?那就是HTML的工作方式。使人迷惑的是两个对象都有value这个属性。对于按钮,value是"Get editable field value",我想应该是按钮的标签,但是域的value值却是它的实际值。一些其他类型的对象同时有value属性和text属性。如果你像我一样,那么你有时就会搞不清楚什么是什么!就我的经验而谈,最简单的办法是读Web页面的HTML代码。

多值
HTML的域没有Notes的域那样的多值属性。可以试一下:在表单上加入第二个按钮和第二个域。把域命名为"Letters",类型为可编辑文本,选中"允许多值(Allow multiple values)"复选框。将默认值写成如下的字母列表:

"A":"B":"C":"D":"E":"F":"G"




把按钮命名为"Get multiple values"并键入如下的JavaScript代码:

alert(document.forms[0].Letters.value);




你可以用不同的分隔符来改变此域的值,但是当你单击按钮时,你会注意到,不论你用什么分隔符,提示你的总是域的所有值。这和在Notes客户端中运行的@Formulas和LotusScript形成了对比。用@Prompt,你得到的提示只是域的第一个值:"A"。你用LotusScript同样也只能显示一个值,但是你要指定数组下标,否则将得到一个错误提示。公式和LotusScript都不能在提示语句中得到多值域的所有值。

原因就是,在Notes的语言中,确实有多个值在域中。对于HTML和JavaScript来说,只有一个值。再次看Web页面的源代码你会发现和下面类似的代码:

<input name="Letters" value="A;B;C;D;E;F;G">




注意它的值是用"一对"双引号引起来的带分隔符的值。以后将会详细讨论如何分隔单独的值,但现在,你应该意识到多值在Web上并不是确切的多值(至少对于文本输入框是如此)。其他类型域的处理方式和文本域将会不同。

单选按钮
另一个有趣的地方是单选按钮,就Notes和Web页面而言,Notes里的单选按钮是一个有多个值的单个域,在Web上是同名的输入文本框的数组。为了理解以上所述,请看下面的例子:

在表单上,加入另一个新域,名字为"RadioButtn"。正像它的名字一样,把它改成单选框类型的域。在域属性窗口的第二个标签中,输入下列选项和别名(图5):



图 5

One | A
Two | B
Three | C
Four | D




把此域的缺省值设成第一个选项的别名,也就是带引号的字母"A"。现在在浏览器里预览表单,再看源文件,你会看到单选按钮的代码和正常域的代码有很大区别。HTML代码看起来将和下面的类似:

<input type="radio" name="RadioButtn" value="A" checked>One<br>
<input type="radio" name="RadioButtn" value="B">Two<br>
<input type="radio" name="RadioButtn" value="C">Three<br>
<input type="radio" name="RadioButtn" value="D">Four




在这里你要注意一些要点。首先,所有的4个单选按钮对象有同一个名字:RadioButtn,这样一来,HTML和JavaScript就知道它们是同一个数组里的对象。其次,每个选项的值是选项的别名,并不是看到的文字(例如"One"、"Two"等)。这和在Notes中保存的是别名是一样的,保存的不是看到的文本(当然如果没有别名的话,保存的值和文本就是一样的了)。最后,你选中第一个选项的方法是在HTML语句中用的"checked"单词,它被加在了第一个单选按钮的语句里。

如果你再加入另外的一个按钮,用和取其他两个域值同样的方法来取RadioButtn的值的话,你会得到一个奇怪的错误,也就是用下面的代码:

alert(document.forms[0].RadioButtn.value);




你将会看到一个提示"undefined"的错误对话框(如图6)。



图 6

这里的问题并不是没有定义它的值。毕竟如上面所示,单选按钮的代码中共有4个值。也就是说,问题出在RadioButtn本身,至少是现在用在这里的那个。单选按钮是一个输入选项的数组,如果你想要知道其中一个元素的值,必须指定是哪一个,试试下面的代码:

alert(document.forms[0].RadioButtn[0].value);




好,返回的是当前域的值"A",但是当你选择其他的选项时再单击按钮,你得到的依然是"A",而不是你所选择的值,还是不太妙。

为了得到选择的选项的值,首先要知道哪个选项被选中了,然后在alert语句中,用那个选中的选项的下标值来正确地引用当前选项的值。也就是说,如果第一个选项被选中,你应该取RadioButtn[0].value,如果第二个选项被选中,你就应该取RadioButtn[1].value,依此类推。

在JavaScript中,某些类型的域具有selectedIndex属性,代表当前选中选项的数组下标值。然而单选按钮并不是那么幸运,同样,复选框也没能逃脱厄运。要想得到当前选中的单选按钮的值,你必须在RadioButtn数组元素中查找"checked"属性。和LotusScript相比,LotusScript就能像操作其他类型的域一样来取得单选按钮当前被选中的值。这是一件非常麻烦的事,但是,它就是那样的。

下面是按钮的代码:

var doc = document.forms[0];
for(i = 0; i <
doc.RadioButtn.length; i++){
if(doc.RadioButtn[i].checked){
alert(doc.RadioButtn[i].value);
break;
}
}




这里马上就出现了几个新概念,让我花点儿时间来解释一下。首先,如果你读过前面那篇文章,你就会知道"var"是在JavaScript里用来声明变量或给变量赋值用的,就好比LotusScript里的"Dim"和"Set"。既然这样,为了避免一遍一遍地输入document.forms[0],我就把document.forms[0]赋给变量doc以备后用:

var doc = document.forms[0];




下面是循环,循环体中没有代码时的样子如下:

for(i = 0; i < doc.RadioButtn.length; i++){
  }




你是不是有点眼花缭乱?我以前每次看到类似这样的代码就眼晕,但是它并不像它看起来那么糟。首先,花括号只是用来包含循环体的。JavaScript的for循环有三个选项:



计数变量以及它的初始值(i=0);
如何知道继续循环(i < doc.RadioButtn.length);
如何累计计数变量(i++)。


首先是i=0,很简单,我使用了变量i并且它的初始值为0。

第二部分:i<doc.RadioButtn.length,它可有点儿不太直观。JavaScript的length属性具有不同的使用环境,如果你要检查一个普通文本域的length,比如在表单上的CreatedBy域(document.forms[0].CreatedBy.length),你会发现length是域中文本的字符个数。比如Anonymous,length就是9。对于数组,比如RadioButtn数组,length是数组中元素的个数。不像数组下标那样从0开始,length从1开始。因此,如果RadioButtn数组的最后一个元素下标是3,length的值就是4。在循环中,我让i从0开始计数循环,直到它小于4为止。因此,循环体共循环4次,i的值分别是0,1,2,3,以数组的最后一个元素的下标结束(我承认有点儿混乱)。

循环体中的第三个参数:i++,对于LotusScript开发人员来说是一个低级错误。这是在JavaScript中的简写方式,i++的值和i=i+1的值是一样的。实际上,你可以在循环中用两种形式的任何一种,所以下面这种写法和上面的写法是等价的:

for(i = 0; i < doc.RadioButtn.length; i = i + 1){
}




i=i+1同样可以正常运行,但是问题是没有人那么做,因为你习惯i++后,它更短小、更简单。它的价值在于,你还可以写i--,和i=i-1是一样的,当然,在这个循环里它不能运行。用i++你还可以做许多看起来很有趣的事情,但那是以后的事了。

再来看循环:三个参数用分号分隔并由圆括号包围,循环体代码用花括号包围,循环体中是一个if语句:

if(doc.RadioButtn[i].checked){
}




这里的判断真假的语句同样也用圆括号包围。试验中的doc.RadioButtn[i].checked看起来没有提供充足的信息,但它和循环一起构成了一个JavaScript的简写方式。如果用LotusScript的方式呢?我首先会去检查当前的RadioButton元素是不是等于checked,像下面的方式:

doc.RadioButton[0] = "checked"




由于checked是一个属性而不是一个值,所以上面的代码不能正确运行。你还会注意到在HTML中它并没有用引号引起来。其实,checked是一种"是"或者"不是"的东西。更准确一点说,它不是真就是假,所以那个if语句的意思就是:如果RadioButtn的这个元素是checked(被选中的),即:为真,那么就做下面的事情......这里的试验看起来有点奇怪,因为始终没有提到真假。如果那让你感到不舒服,你还可以很轻松地这样写if语句:

if(doc.RadioButtn[i].checked == true){
}




注意这里的true全部是小写而且有两个等号。和LotusScript中不同,JavaScript里的等号(=)只是用来把一个值赋给另一个什么东西:

var doc = document.forms[0];




为了比较两个项目是否相等,你必须使用两个等号。在我的头脑里,我想它的意思是:doc.RadioButtn[i].checked等于true,这样来帮我记住要用两个等号。双符号标记同样适用于&符号(使用一个时用来追加或连接字符;使用两个时表示"and",比如在一个if语句里用两个判断条件时)。

最后,在if语句里是一个alert语句,紧跟着一个break。break就是JavaScript里的Exit For。它终止循环,因为一个单选按钮只能有一个选项被选中。

如果你把所有的代码都放入按钮里,你就会看到无论你选择单选按钮的哪个选项,单击按钮后都能正确的显示出选项的值。非常棒,现在你对JavaScript已经入门了。

复选框


复选框和单选按钮类似。在表单上,复制单选按钮域并改名为"CheckBx",更改域的类型为"CheckBox(复选框)",保存表单,刷新Web页面并查看源文件。你将看到复选框的HTML代码和RadioButtn的几乎一模一样:

<input type="checkbox" name="CheckBx" value="A" checked>One<br>
<input type="checkbox" name="CheckBx" value="B">Two<br>
<input type="checkbox" name="CheckBx" value="C">Three<br>
<input type="checkbox" name="CheckBx" value="D">Four




真正的区别不是域名,而是类型是复选框,不是单选按钮。另外一个区别就是你可以选择复选框中的多个值,尽管你还要像操作单选按钮那样遍历整个复选框来确定哪个选项被选中,但是你不能在全部检查完是否选中之前停止遍历动作。按钮中用来检查复选框选中的代码会像下面的样子:

var doc = document.forms[0];
for(i = 0; i < doc.CheckBx.length; i++){
if(doc.CheckBx[i].checked){
alert(doc.CheckBx[i].value);
}
}




我确信到现在为止,你应该多多少少熟悉这些代码了,因为这和单选按钮基本一样,除了域名的改变和去掉了"bread"语句。在一个实用的程序中,这些代码所做的工作比我做的要多得多,但是首先我希望你很舒服地学完这些基本内容。

等待更多的对象
你还有几个类型的域需要了解,每一种都有自己的特性,但那是另一篇文章的素材。现在,你可能要用自己的试验来熟悉这里的例子了。你也可能要向表单中加入更多的、我还没有涉及到的域,并查看它们的HTML源文件,那是我们下次的开始部分,再见。
Program | 评论(0) | 引用(27) | 阅读(3931)