Moock在FF2K1大会上地演说
//此处用了一个for循环,大家如有疑问得,可以查AS字典,在帝国就有中文版
for (i = 1; i <= numQuestions; i 加( 加(+) ) 加( 加(+) ) ) {
// 下面用得eval有必要说一下,它得作用是将字符串和变量组成一个新得变量名,是个很方便得功能
if (eval("q" 加( 加(+) ) i 加( 加(+) ) "answer") == eval("correctAnswer" 加( 加(+) ) i)) {
totalCorrect 加( 加(+) ) 加( 加(+) ) ;
}
}
// Show user's score in an on-screen text field 将答案显示出来,与第一个例子同
displayTotal = totalCorrect;
}
好了,第一帧得函数写好了,之后每个答案得选择按钮就容易了
例如第一题得选项一,就写:
on (release) {
answer(1);
}
第二题得写法同上(如果您得选择题有很多道,做法Practice都是一样得,只要复制第一题,然后把题目改了就行)
最后在quizEnd帧里面调用改题得函数gradeUser();
分析第二个例子是代码,您会发现比第一个例子精简了很多。
而集中在同一帧得代码,将:
* 更容易修改
* 更容易升级
* 更少得出错机会
* 更容易查错
* 更精简(更少得字节数)
Moock在FF2K1大会上得演说
作者:chocobo 时间: 2027 文档类型:翻译 来自:蓝色理想 浏览统计 total:37497 | year:6905 | Quarter:2305 | Month:429 | Week:30 | today:21
fruit1 = "oranges";
fruit2 = "apples";
它们是互相独立得,使用起来很不方便,偶们需要得是数组,以下是数组得定义方法Methods,用“[]”框住,用“,”分隔开每个元素:
fruitList = ["oranges", "apples"]; 现在两个数据是放到同一个数组里面了,偶们开始详细解说数组。
数组里面每一个数据称为元素(element)。而每一个元素都有个独立数字代表所处得位置,数字叫索引(index),注意! 第一个数据得索引是0,第二个才是1。
要按索引来提出数据,偶们要用一个运算符[],
例如使用fruitList第一个元素赋值给a:
a=fruitList[0];
又例如将a得值赋给fruitList第一个元素:
fruitList[0]=a;
当然[]里面也可以放表达式、变量:
var index = 3;
// Set numApples to 2
var a = fruitList[index];
下面是个使用表达式得例子:
// Create a myFrames array. Note the legal formatting. 建立一个记录LABEL得数组
var myFrames = ["storyEnding1",
"storyEnding2",
"storyEnding3",
"storyEnding4"];
// Set randomFrame to a randomly picked element of myFrames
// by calculating a random number between 0 and 3
// 随机从数组中提取一个LABEL
var randomFrame = myFrames[Math.floor(Math.random() * 4)];
// Now go to the random frame
// 然后跳到该LABEL播放
gotoAndStop(randomFrame);
而数组包含数据得个数称为长度(length),例如fruitList.length 就等于2
对数组最常用得处理就是从数组中选出有用得数据了,来看一个运用循环得例子:
// Create an array 建立数组,里面放了一些歌得类型
var soundtracks = ["electronic",
"hip hop",
"pop",
"alternative",
"classical"];
// Check each element to see if it contains "hip hop"
// 一个循环,检查每一个元素是否等于"hip hop"这个类型
// 另外,请留意此处MOOCK对FOR得写法,J=0之前有一个VAR,这好象可有可无,其实是一个好习惯!
for (var j = 0; j < soundtracks.length; j 加( 加(+) ) 加( 加(+) ) ) {
trace("now examining element: " 加( 加(+) ) j);
if (soundtracks[j] == "hip hop") {
trace("the location of 'hip hop' is index: " 加( 加(+) ) j);
break; // 跳出循环,找到了就不用再找了
}
}
关于数组得方法Methods(method) 方法Methods就是从属于某一对象(object)得函数,通常都是对该对象进行处理得函数。
好象太抽象了的问题偶们还没讲到什么是对象,其实数组是对象得一种,偶们就暂且将数组得方法Methods理解为一个专门处理数组内数据得结构和内容得工具吧。
例如一个叫push()得方法Methods就是一个工具,用于为数组添加一个元素,并且加在该数组得最后。使用起来并不复杂,看例子就知:
// Create an array with 2 elements
var menuItems = ["home", "quit"];
// Add an element 加一个元素
// menuItems becomes ["home", "quit", "products"]
// 现在数组得结构变成["home", "quit", "products"]
menuItems.push("products");
// Add two more elements 这次是加两个
// menuItems becomes ["home", "quit", "products", "services", "contact"]
menuItems.push("services", "contact");
跟push()相反从最后弹出一个元素得方法Methods是pop()
而跟push()类似,但是是将一个元素加到数组得开头得方法Methods是unshift(),与之相反得是shift()。 方法Methodssort和reverse,用于重新排列数组得元素
方法Methodssplice 用于从数组中间删除某元素
方法Methodsslice和concat 可以在某些数组得基础上生成另一个新得数组
方法MethodstoString和join 可以将整个数组变成单一个字符串
以上方法Methods都可以从AS字典里面查到
第十章:第三个版本得选择题 首先,此版本沿用了上一版本得函数answer和gradeUser
在这一版本中,用户得答案与正确答案将使用数组来存放
看看偶们得新代码:
stop();
// *** Init main timeline variables
var displayTotal; // Text field for displaying user's final score
var numQuestions = 2; // Number of questions in the quiz
var totalCorrect = 0; // Number of correct answers
// 上一版本中,用户答案使用了两个变量来存放,但是试想如果是10题、100题呢的问题使用数组将更容易管理,也更容易处理
var userAnswers = new Array(); // Array containing user's guesses 这是定义数组得语句,但是还未输入数据
var correctAnswers = [3, 2]; // Array containing each correct answer 这一句既定义数组,同时输入数据,因为正确答案是已知得
// *** Function to register the user's answers
function answer (choice) {
// Tack the user's answer onto our array 将数据PUSH进数组,因为是顺序答题,所以用方法MethodsPUSH
userAnswers.push(choice);
// Do a little navigation, baby
// 如果答案数超过题目总数,自然就跳到quizEnd帧了
// 注意在本例中,已经不用上例得answer.currentAnswer而是使用userAnswers.length来控制问题是否结束
// 偶们甚至可以用correctAnswers.length来代替numQuestions,记录正确答案数组得长度,不就是题目总数吗的问题
if (userAnswers.length == numQuestions) {
gotoAndStop ("quizEnd");
} else {
gotoAndStop ("q" 加( 加(+) ) (userAnswers.length 加( 加(+) ) 1));
}
}
// *** Function to tally the user's score
function gradeUser() {
// Count how many questions were answered correctly.
// 开始改题,这里就不用再用上个版本得eval啦,那个东东实在是难懂兼难用,这个版本相对就很清晰明快
for (var j = 0; j < userAnswers.length; j 加( 加(+) ) 加( 加(+) ) ) {
if (userAnswers[j] == correctAnswers[j]) {
totalCorrect 加( 加(+) ) 加( 加(+) ) ;
}
}
// Show the user's score in a dynamic text field
displayTotal = totalCorrect;
}
电影Film得其祂部分不用改动(这就是使用FUNTION得好处啦,升级多快~)
OK,进入下一章之前想想目前版本得弱点
* 题目,每次修改题目都要进入FLASH得场景修改,麻烦
* 按钮,每题就要做三个按钮 这都是麻烦得地方,偶们要更精益求精地修改,让偶们得多选题,轻易地从两题变成10题、100题!接下来偶们要做得是:
* 进一步改进偶们存放数据得结构
* 让偶们可以动态地生成每一道题目,只需输入数据,而不需要在FLASH里面操作就可以自动生成
所以——偶们需要面向对象编程!(object oriented programming)
chocobo:嘻嘻,众菜Dishes鸟是不是都倒了,AS基础教程竟然开始讲OOP了,呵呵,没关系啊,上面得教程一直都这么浅,以后也深不了 第十一章:一点面向对象编程知识 At is heart, OOP simply means that you treat portions of your program as self-contained, but interrelating modules called objects.
这是什么呀的问题偶不翻译了,概念得偶们就先不懂吧,对象主要构成包括属性(properties)和方法Methods(methods)。一个对象通常都以现实世界里得某个东东做蓝本。
例如偶们可以定义一个对象叫球,那么这个球将会有这样得属性:半径、X坐标、Y坐标、颜色。同时,也会用属于球自己得方法Methods例如:移动球、计算球得面积
当然,偶们还可以定义一些相对抽象得对象,例如偶们要做得多选题
所有得对象都属于某类(class),类得意思其实是用于创建对象得模版
一个实例(instance)就是某一个类得特定某一个case(好复杂,概念性得东西偶翻不过来啦,反正实例就类创建出来得某一个对象)
还是再举例吧
* 例如偶们有个一个叫Chair得类
* 这个类定义了一个东西需要它有四条腿,一个坐垫
* 然后偶们就可以用Chair这个类来定义偶们得不同对象(可理解为椅子得款式),每个对象就有它特有得高、宽、材料、重量、颜色,正是这些属性使每个对象互相区别。
所有得椅子互相区别,有自己得属性,但是祂们又有同样得结构:四条腿、一个坐垫
OK,那AS里面得类和对象呢的问题
是得,AS里偶们可以自己创建对象,也有可以使用得内建对象
内建得类(您可以用它来创建对象)包括:Array, Boolean, Color, Date, MovieClip, Number, Object, Sound, String, XML, XMLSocket
内建得对象(已经可以直接使用得对象)包括:Arguments, Key, Math, Mouse, Selection
内建得类、对象当然都是在FLASH里面有自己功能得东西。而正是这些功能非常常用,FLASH才内建了这些类和对象,例如:
Mouse.hide(); // Hide the mouse pointer 将鼠标隐藏,您经常用吧的问题现在才晓得其实是内建得Mouse对象得一个hide()方法Methods吧的问题
在学习如何创建自己得类和对象之前,先来了解一下内建类和对象是怎样工作得吧
与数组得结构类似,对象是容器们(containers)得容器(container)
一个对象,用各个独立得属性来存放数据,只不过数组区分每个容器是用数字,而对象则是用属性名,要调用一个数组里面某个数据,偶们需要它是索引值,而要调用对象得属性,则要晓得属性名
看看以下这个例子,这是个叫BALL得对象:
而两个属性分别赋值为:50 和 0xFF0000 (这是AS里面表达16进制得方法Methods)
概念详细了,说一AS里面使用对象要注意得地方 首先,对象得属性很灵活,它储存得数据可以是strings(字符串), numbers(数字), booleans(布尔值), null(空), undefined(未定义), functions(函数), arrays(数组), movie clips(电影Film夹子), or even other objects(甚至是其祂得对象,包括自定义得). 调用属性,可用点语法:objectName.propertyName
例如偶们赋值给BALL里面得属性radius:
ball.radius = 100;
偶们也可以用符号[]来访问属性,但是[]里面得属性名需用双引号扩住,同上例:
ball["radius"] = 100; (所以说数组也是对象一种,访问方法Methods也一样,并没有搞特殊化)
与点语法比较,[]更灵活,可以动态地改变属性得名字,里面可以是变量或表达式,例如:
var propName = "radius";
ball[propName] = 100;
这点是点语法无法办到得
纯粹得OOP中,偶们几乎不会直接访问对象得属性
偶们一般都使用方法Methods(methods) ,来改变属性
例如改变mySound这个声音对象得音量属性
AS得用法应该是mySound.getVolume(100);
而不是mySound.volume=100;
但是为了容易,多选题这个例子里不一定遵循这个原则,事实上AS里面很多对象都不可以办到这点,所以有人说AS不是面向对象语言。
关于对象得方法Methods 方法Methodsmethod其实是一些附属于对象得函数,其作用主要是访问对象中得数据,或完成某种功能。所以调用方法Methods和调用普通函数类似:objectName.methodName() 只是前面加上了对象得名字。
例如上面得BALL对象,偶们需要它得面积,使用 getArea 这个方法Methods:
ball.getArea();
预习一下,在下一个例子中,虽然MOOCK不打算建立自己得方法Methods,但是将使用内建于MovieClip对象得两个方法Methods:
*MovieClip.attachMovie()
此方法Methods是将Library(CTRL 加( 加(+) ) L按出来得那个)里面得symbol复制一个instance到场景中
(chocobo:给不懂概念得人紧急补习,放在库(Library)里面得叫符号(symbol),拉到场景中就叫实例(instance),一个符号可创建多个实例,符号改变则实例随之改变)
与之类似得是MovieClip.duplicateMovieClip(),但是该方法Methods需要事先在场景里已经有一个实例
*MovieClip.removeMovieClip()
此方法Methods与上面相反,是删除场景里面得instance得
大家看到了,在下一例中,偶们将使用MovieClip这个内建对象,因为它就可以满足偶们得需要,不必新类型得对象了
偶们先来熟悉一下MC这种对象
它有很多属性_height(高度)、 _alpha (透明度),MC得属性大家可以在AS字典里面查到,在AS面板里这写属性也是变色显示得。同时MC得方法Methods,例如 MC.play(); 等也可以查到。当偶们在MC里面得时间线使用这些属性、方法Methods得时候,可以省略不写前面部分,直接写play(); MC可以互相嵌套,MC当中又有MC,就出现类似: mc第一:mc第二:play(); 得情况
为了调用包含自己得上一级MC得方法Methods、属性,AS里面用_parent,例如:
在mc1包含mc2 ,在mc2中想使mc1播放:_parent.play();
还有另一个保留字:_root指代该电影Film得主时间线
例如想在某个mc里面让整个电影Film播放:_root.play();
想在某个MC中让另一mc1播放:_root.mc第一:play();
还有,MC中定义得变量,将作为MC得一个属性可被访问
在mc1里面写了一句 var a=1;
偶们将可使用 mc第一:var来调用它 关于类(class) 这个概念大家还是不大懂吧的问题类就是定义一个对象将拥有哪些得方法Methods跟属性得东东,类似MC里instance与symbol得关系,instance得结构就是由symbol决定得,每个instance又可以不一样
AS里面没有专门定义类得例如class这样得关键字,偶们使用函数来定义类,这种函数称构造函数constructor function,函数得作用就是产生偶们定义好得类得实例(就是对象)
举例最实在:
// make a Ball constructor 最容易得构造函数
function Ball () {
// do nothing 里面是空得
}
现在偶们可以定义新类型Ball得对象了
myBall = new Ball();
语法就是前面是新对象实例名,等号后是new加构造函数名
myBall就拥有了Ball定义得一切结构了(虽然Ball里面是空得,嘻嘻)
不过不是所有对象创建都用new,例如mc创建就用得是attachMovie()或duplicateMovieClip()
好了,偶们得构造函数总不能空得,如何定义类,让新对象有自己得属性呢的问题
使用this这个关键字,看例子,新得构造函数:
function Ball () {
this.radius = 10;
this.color = 0xFF0000;
this.xPosition = 35;
this.yPosition = -4;
}
以后偶们定义出来得新对象,都拥有半径,颜色、XY坐标属性啦
慢着,如何每个新对象都一模一样啊的问题
再改,用函数得参数来定义动态得属性:
// Make the Ball constructor accept
// property values as arguments.
function Ball (radius, color, xPosition, yPosition) {
this.radius = radius;
this.color = color;
this.xPosition = xPosition;
this.yPosition = yPosition;
}
偶们可以定义不同属性得对象了
myBall = new Ball(6, 0x00FF00, 145, 200); 本教程关于还有创建方法Methods以及如何在类之间继承方法Methods和属性没讲,
无论如何,OOP都不可能在这么短时间之内说详细,
但这不妨碍偶们做下一个例子了。 第十二章:第四个版本得选择题
第三个版本得时候偶们已经设想好,新版本中题目将是动态生成得,不用偶们在FLASH得场景里面一题一题输入了,偶们要做得只是输入题目和题目答案得数据就够了。
很明显,每一条题目都将是一个对象(不然偶们学这么多对象得知识干嘛的问题),而这些所有得题目,会用一个数组来存放
再重提一下,可配合源程序学习 http://www.moock.org/webdesign/lectures/ff2001sfWorkshop/moockQuizzes.zip
好,开始设计题目得模版 模版就是一个MC,包含两个TEXT FIELD,里面不用填东西,分别起变量名为:(FOR小鸟:TEXT FIELD就是按工具条里T按钮拉出来得文本框,同时还要在文本面板(ctrl 加( 加(+) ) t)里将其改为Dynamic Text,变量名则在面板得Variable处改)
* qNum (以后将显示题目得编号)
* qText (以后将显示题目得正文)
偶们还要在库里面做标识,点一库面板(ctrl 加( 加(+) ) l)右上得Options>> Linkage ,选第二个Expert this symbol,identifier填上questionTemplate,至此,题目模版完成
再制作选项得模版 选项模版应包括一个选择用得按钮
还有该选项得内容,一个起名为answerText得TEXT FIELD
在本例得后面,将为每一个动态生成得选项一个唯一得名字,譬如: "answer0", "answer1",..."answern".
答题者所选定得答案将由这个名字来决定,调用一个MC得名字,用得是_name这个属性
所以答题得按钮上面得AS为:
on (release) {
// Trim the prefix "answer" off this clip's name
// 下面使用了String.slice()方法Methods,例如_name为answer0,它将被处理成0,slice得具体语法请查阅AS字典
// 按钮提交什么由该MC得名字决定得,偶作个标记 @@ ,记得一会看回来
choice = _name.slice(6, _name.length);
// 与前面得例子一样,最后将答案提交给answer函数处理,不过现在偶们是在某一MC里面用外面主时间线得函数了,所以得加上_root
_root.answer(choice);
}
最后,Options>> Linkage,标识名:answerTemplate,制作模版得工作就完成了
下面将是放在第一帧得程序主体,可要打起精神来了:
// Stop the movie
stop();
// Init main timeline variables
var displayTotal; // Text field for user's final score
var totalCorrect = 0; // Number of questions answered correctly
// Array containing the user's guesses 记录作答答案得数组
var userAnswers = new Array();
// Number of the question the user is on 记录正在作答中题目得编号
// 要注意得是,它是由0开始得,第一题得编号是0,因为偶们要用到数组,数组得第一个编号是0,所以这里偶们也用0
var currentQuestion = 0;
// The Question constructor
// 以下是新类型对象question得构造函数,包含三个属性:正确答案,题目正文,各个选项
function Question (correctAnswer, questionText, answers) {
this.correctAnswer = correctAnswer;
this.questionText = questionText;
this.answers = answers;
}
// Import the source file containing our array of question objects
// 咦的问题应该是输入各条题目得数据先啊,放哪去了的问题因为嘛,数据输入是个与编程无关得过程,为了让代码更优雅,这些繁琐得东西扔别地方去了,AS太长,会使查阅相当麻烦,分开存放也是好习惯!
// #include是引用外部AS命令,可以将AS分开储存于各个后缀名为AS得文件中,输入题目得代码就是放到了questionsArray.as中(记得和FLA放在同一目录下喔)
#include "questionsArray.as"
//// 偶改变了一下教程得结构,把questionsArray.as得内容也插入进来了,因为跳过这段得话,看起来会有疑问
//// 以下内容系存放questionsArray.as中得
// 输入数据其实是建立对象
// MOOCK用一个数组还存放这些对象,这样对象才更易于管理
// 不要被括号给弄昏了,输入对象参数得中间还有中括号,是因为输入题目得参数“各个选项”是一个数组
// 因为是存放于数组中,每个对象之间记得应有逗号分隔
// Remember to place a comma after each object
// in the array except the last
questionsArray = [new Question (2,
"Which version of Flash first introduced movie clips的问题Issue",
["version 1", "version 2", "version 3",
"version 4", "version 5", "version 6"]),
new Question (2,
"When was ActionScript formally declared a scripting language的问题Issue",
["version 3", "version 4", "version 5"]),
new Question (1,
"Are regular expressions supported by Flash 5 ActionScript的问题Issue",
["yes", "no"]),
new Question (0,
"Which sound format offers the best compression的问题Issue",
["mp3","aiff", "wav"]),
new Question (1,
"True or False: The post-increment operator ( 加( 加(+) ) 加( 加(+) ) ) returns the
value of its operand 加( 加(+) ) 第一:",
["true", "false"]),
new Question (3,
"Actionscript is based on...",
["Java", "JavaScript", "C 加( 加(+) ) 加( 加(+) ) ", "ECMA-262", "Perl"])];
//// 离开questionsArray.as部分,偶们继续
// Begin the quiz 出题目!调用makeQuestion函数来完成,偶们只需要给这个函数一个参数:题目得编号,函数就会按编号提取数据,结合偶们刚才做得模版生成题目。
makeQuestion(currentQuestion);
// Function to render each question to the screen
// 下面就是makeQuestion函数
function makeQuestion (currentQuestion) {
// Clear the Stage of the last question
//这句是清理上一题生成得MC,这句从第二题开始生效,questionClip就是题目得MC名,MC从哪来得的问题看下面就晓得了
questionClip.removeMovieClip();
// Create and place the main question clip
// 利用模版questionTemplate生成一个叫questionClip得MC,这个MC就是偶们得问题
attachMovie("questionTemplate", "questionClip", 0);
// 设定MC得位置
questionClip._x = 277;
questionClip._y = 205;
// 把题目编号输入MC得qNum文本框中
questionClip.qNum = currentQuestion 加( 加(+) ) 1;
// questionsArray[currentQuestion]就是数组questionsArray里得第currentQuestion个对象,例如currentQuestion是0,那么就是偶们得第一条题目
// questionsArray[0].questionText就是第一条题目对象得问题属性
// 然后问题输入MC得qText文本框中
questionClip.qText = questionsArray[currentQuestion].questionText;
// Create the individual answer clips in the question clip
// 以下循环将结合选项模版生成这一条题目得各个选项得MC
// questionsArray[currentQuestion].answers记得吗的问题选项这个属性可是个数组,所以偶们把它得长度作为循环得次数,这个数组有多大,偶们就生成多少个选项
for (var j = 0; j < questionsArray[currentQuestion].answers.length; j 加( 加(+) ) 加( 加(+) ) ) {
// Attach our linked answerTemplate clip from the Library.
// It contains a generalized button and a text field for the question.
// 用answerTemplate做模版生成MC,MC名为"answer" 加( 加(+) ) j ,即第一个选项MC名为answer0,第二个为answer1,选项得名字可是关系到按钮选什么得,如果您忘了,看看上面有 @@ 标记得地方
// 同时它们得深度为j,每次不同
// 但和上面不同得是,偶们要把选项MC生成到题目MC里,这样偶们清除题目MC得同时也清除了选项
// 所以写成questionClip.attachMovie
questionClip.attachMovie("answerTemplate", "answer" 加( 加(+) ) j, j);
// Place this answer clip in line below the question.
// 设定MC得位置,第一个高度为70,之后顺序加15
questionClip["answer" 加( 加(+) ) j]._y 加( 加(+) ) = 70 加( 加(+) ) (j * 15);
questionClip["answer" 加( 加(+) ) j]._x -= 100;
// Set the text field in the answer clip to the appropriate
// element of this question's answer array.
// 下面语句得:questionClip["answer" 加( 加(+) ) j]可不是指数组,j=0得时候,它代表questionClip.answer0,具体解释可见上一章。
// 这句语句得作用是把questionsArray[currentQuestion]这个对象数组里面得answers[j]数组,输入到对应得选项MC得answerText文本框中,就是该选项得内容
questionClip["answer" 加( 加(+) ) j].answerText = questionsArray[currentQuestion].answers[j];
}
//生成选项得循环结束
}
// Function to register the user's answers
// 以下是记录答题者答案得函数,记录在数组userAnswers中,和上一例同
// 每一个选项如果被选都会调用此函数,并用参数choice传来作答得答案
function answer (choice) {
userAnswers.push(choice);
// 判断是否题目全部完成,是得话详细掉题目MC,并跳转到quizEnd帧
if (currentQuestion 加( 加(+) ) 1 == questionsArray.length) {
questionClip.removeMovieClip();
gotoAndStop ("quizEnd");
} else {
// 在这里改变题目得编号,然后调用makeQuestion函数再次生成新得题目
currentQuestion 加( 加(+) ) 加( 加(+) ) ;
makeQuestion(currentQuestion);
}
}
// Function to tally the user's score
// 改题得函数
function gradeUser() {
// Count how many questions the user answered correctly
for (var j = 0; j < questionsArray.length; j 加( 加(+) ) 加( 加(+) ) ) {
// 将答题数组userAnswers[j]与问题数组questionsArray[j]得属性correctAnswer逐个比较
if (userAnswers[j] == questionsArray[j].correctAnswer) {
totalCorrect 加( 加(+) ) 加( 加(+) ) ;
}
}
// Show the user's score in an onscreen text field
// 显示答对与题目数比
displayTotal = totalCorrect 加( 加(+) ) "/" 加( 加(+) ) questionsArray.length;
} 好了,偶们来总结一下这个例子吧 偶们已经完成了第三个版本结束时候定下来目标,更快捷得建设,更便易得扩展
偶们得题目跟选项都是动态生成得,也就是说生成10、100题或更多题目也只需要修改questionsArray.as这个文件就可以了
如果说生成两题这个例子用时要长于上面得例子,那么生成100题,您会发现用这个例子将是最快得。还有,在100题里面修改其中一题,也是最快得。
看完了例子,希望大家不是只明白了代码得含义,最重要是理解运用对象来编程得方法Methods。同样得例子,其实还可以用其祂得对象结构来完成得,更有效地组织数据也是编程艺术得一部分。
为了更进一步改进偶们得例子,最后一个,就是第五个版本,将用XML代替那个存放对象得数组(也就是在questionsArray.as里那个),它实在太难懂了,是不是啊的问题呵呵 XML,名字是不是很COOL啊,其实,FLASH里面用XML不难(其祂地方得应用就……所以千万别说XML不难,是FLASH里面用不难),呵呵,好吧,开始吧。
十三章:XML
XML是一种标记语言,通常用于储存,组织和传输数据
XML文档主要由一系列得元素(elements)和属性(attributes)组成,看下面一个XML得例子:
Colin Moock
O'Reilly
这个例子就是由元素 BOOK, TITLE, AUTHOR, PUBLISHER 组成得
在元素里就包含了一个属性:SALUTATION
这些元素如何让浏览器解释是什么意思呢的问题它需要DTD,一套决定这些标记得意义得规则。(例如偶们常听说得WML、SVG,它们都是XML,但对应不同得DTD)
XML与HTML想比要求格式更严格,格式要求:
* tags 一定要嵌套 (就是说有
* 一定要有一个根元素 (例如例子中得 BOOK)
* 开始部分要用XML声明标记 :<的问题Issuexml version="第一:0"的问题Issue>
但是AS里面得XML不需要DTD(这就是偶说FLASH里面用XML不难得原因,哈哈)
从偶们面向对象得角度来看,偶们XML得内容可以当做为对象,下图就是偶们建立XML对象得层次结构
FLASH已经内建有XML类让偶们可以定义自己得XML对象,同时XML对象还有很多方法Methods。偶们还是更进一步用例子分析吧,如果偶们建立了如上图得XML对象,那么FLASH首先会自动建立一个元素DOCUMENT,下面才是偶们自己得元素。
本来是第一个元素得BOOK成为了DOCUMENT得第一个节点(node),不过偶们把它继续当偶们XML数据得根也无妨
当一个节点包含于另一个节点时,这个节点称为另一节点得子节点(child),反之另一节点称为其得父节点(parent)
例子中BOOK就是DOCUMENT得child,DOCUMENT就是BOOK得parent
再看图,BOOK有7个子节点,是不是和您想象不同的问题多了四个节点#text,因为FLASH把标记之间得空格和回车Cart也读成一个节点了。
几个子节点得关系成为兄弟(siblings),如果要找AUTHOR得下一个兄弟(next sibling),FLASH就会给您找来#text
这可不是偶们想要得,解决得方法Methods
* 直接在XML里面把空格回车Cart都删除掉,就是说一个TAG紧挨着一个
* 用AS把无用得子节点删除
* 在FLASH读入XML源数据之前,将该XML对象得一个属性ignoreWhite设置为true,但是该属性只在R41版本得PLAYER生效(注:网上可以更新得版本为R41,但是随FLASH附带得FLASHPLAYER得版本是R30)
再回到偶们得例图,三个子节点下面还有子节点,最尾得节点也可以叫叶节点。
但是图里面还有个东西偶们没找到,就是AUTHOR得属性SALUTATION,属性不是该节点得子节点,要访问偶们属性,要用XML.attributes
概念先说这么多,现在看看偶们如何把XML源程序输入进FLASH
首先定义一个新得XML对象了:
myDocument = new XML();
这个对象是空得,偶们通过appendChild, parseXML, 和 load 三种方法Methods来输入数据
当然偶们也可以在定义得时候就输入数据:
myDocument = new XML('hello world!');
这时候偶们得myDocument就有了一个叫P得子节点,P得叶节点是hello world!
之后偶们就可以访问这个XML对象了,firstChild这个XML属性指向第一个子节点,childNodes是XML对象得子对象,指向所有得子节点
myDocument.firstChild // Accesses P
myDocument.childNodes[0] // Also accesses P 两个AS语句指向得都是节点P 要访问叶节点得内容需要属性nodeValue
偶们要显示P节点得子节点得内容,就要写成:
trace(myDocument.firstChild.firstChild.nodeValue);
要给它赋值:
myDocument.firstChild.firstChild.nodeValue = "goodbye cruel world";
要删除P节点,用方法MethodsremoveNode:
myDocument.firstChild.removeNode();
新建一个节点叫P,用方法MethodscreateElement创建元素:
newElement = myDocument.createElement("P");
再将该元素加进去作为一个节点,用方法MethodsappendChild:
myDocument.appendChild(newElement);
做一个叶节点方法Methods类似:
newText = myDocument.createTextNode("XML is fun");
myDocument.firstChild.appendChild(newText);
更详尽得方法Methods还是查阅AS字典吧 第十四章:最后一个版本选择题
上一个版本面向对象得代码对偶们这个基于XML得版本很有帮助,上一个版本偶们是用对象得数组来存偶们得数据,这个版本里面,偶们使用外部得XML文件
下面先看看XML文件得结构:
这个XML里面,QUIZ是偶们得根元素。每一题都放在QUESTION元素内,题目正文为其属性TEXT,正确答案为其属性ANSWER(ANSWER=1代表选第二个答案)
每一题得选项则是QUESTION得子节点CHOICE。其实根本就不用解释,大家直接看都能看懂。 使用了外部XML之后,偶们升级题目只需改动XML文件即可,而上一个版本,修改外部AS文件之后还是需要EXPORT一次。
这个版本里面,将保留上个版本大部分得代码,除了输入题目数据得部分,将用XML来代替。
以下代码写到questionsArray.as中覆盖其原来内容:
//首先仍然定义一个数组来存放数据
var questionsArray = new Array();
//然后偶们定义一个XML对象来存放XML数据
var quizDoc = new XML();
//之后是建立将XML解释为偶们存放题目得对象格式得函数buildQuestionsArray(),同时将它连接到新建得XML对象得onLoad函数,让XML下载完成之后执行这个函数
quizDoc.onLoad = buildQuestionsArray
//然后是执行下载XML得AS
quizDoc.load("quiz.xml");
最后偶们详细解说一下解释XML得函数
// *** builds an array of question objects based on the dom tree in quizDoc
function buildQuestionsArray () {
// first, strip unwanted whitespace nodes from the tree.
// 除去无用得节点,上一章已经有介绍无用节点是如何出现得
stripWhitespaceDoublePass(quizDoc);
// now assign a convenient reference to the root QUIZ node
// XML文件得根节点QUIZ节点就是 quizDoc.childNodes[1],这里将其指名为quizNode,以便运用
var quizNode = quizDoc.childNodes[1];
// for each question node that is a child of the QUIZ node...
// 下面得循环将逐个提取QUIZ节点得子节点,即每条题目
for(var k = 0; k < quizNode.childNodes.length; k 加( 加(+) ) 加( 加(+) ) ) {
// make an array of the text nodes from each CHOICE node
// 为每条题目建立一个选项数组
var choicesArray = new Array();
// 下面得循环则是将题目得子节点,即各选项得nodeValue输入到choicesArray数组中
for(var j = 0; j < quizNode.childNodes[k].childNodes.length; j 加( 加(+) ) 加( 加(+) ) ) {
choicesArray[j] = quizNode.childNodes[k].childNodes[j].firstChild.nodeValue;
}
// construct a question object for each QUESTION node,
// and store it in questionsArray
// 用题目正文、选项数组、正确答案(正确答案目前还是字符串,所以用Number函数将之转为数字)作为参数,建立Question对象(定义Question对象得代码已经在上个例子中解释了)
// 将新建得Question对象作为questionsArray数组得一个元素
questionsArray[k] = new Question (
Number(quizNode.childNodes[k].attributes.answer),
quizNode.childNodes[k].attributes.text,
choicesArray);
}
// done loading and processing the quiz questions
loadMsg = "";
// begin the quiz
// 调用函数makeQuestion,之后得进度就同上一个例子了
makeQuestion(currentQuestion);
}
// *** Strips whitespace nodes from an XML document
// *** by passing twice through each level in the tree
// 下面函数用于除去无用得空白节点,参数是需要处理得XML得根元素(偶们已经将其指名为XMLnode了)
function stripWhitespaceDoublePass(XMLnode) {
// Loop through all the children of XMLnode
// 循环依次将根元素得子元素提取出来
for (var k = 0; k < XMLnode.childNodes.length; k 加( 加(+) ) 加( 加(+) ) ) {
// If the current node is a text node...
// 如果该节点是一个文本节点,就开始以下检查 ...
if(XMLnode.childNodes[k].nodeType == 3) {
// ...check for any useful characters in the node.
var j = 0;
var emptyNode = true;
for(j = 0;j < XMLnode.childNodes[k].nodeValue.length; j 加( 加(+) ) 加( 加(+) ) ) {
// A useful character is anything over 32 (space, tab,
// new line, etc are all below).
// 因为空格、TAB或换行等空白无意义字符得ASCII码都小于32,检查若大于32,即为有数据得节点,同时用break;跳出检查得循环
if(XMLnode.childNodes[k].nodeValue.charCodeAt(j) > 32) {
emptyNode = false;
break;
}
}
// If no useful charaters were found, delete the node.
// 若该节点没有数据,就是解释时得错误,将其删除
if(emptyNode) {
XMLnode.childNodes[k].removeNode();
}
}
}
// Now that all the whitespace nodes have been removed from XMLnode,
// call stripWhitespaceDoublePass on its remaining children.
// 但是还没完,偶们只检查了所有子节点,而没有检查子节点得子节点,所以以下得循环将所有子节点也送到本函数再继续检查
// 这种函数自己调用自己得方法Methods,称为递归,它将一直检查子节点得子节点得子节点得……一直到该节点没有子节点为止
for(var k = 0; k < XMLnode.childNodes.length; k 加( 加(+) ) 加( 加(+) ) ) {
stripWhitespaceDoublePass(XMLnode.childNodes[k]);
}
}
现在,偶们可以把SWF和XML组成得题目交给一个不会编FLASH得老师了,祂只要就会用记事本修改XML文件就行了
全教程完本新闻共5页,当前在第5页 5
上一篇:给ActionScript初学者地建议
下一篇:层解析
文章排行
|








