
原文地址http://www.adobe.com/cfusion/knowledgebase/index.cfm?id=kb400730
在IE浏览器中,Flash或者Flex影片在form标签内用ExternalInterface在JavaScript和ActionScript之间通信时会失效。
当载入、刷新、关闭页面或者关闭浏览器时,会产生如下的错误:
[问题的提出]:Action面板中的代码提示可以提高我们键入代码的效率,但是默认的代码提示并不能完全满足要求,比如在编写代码时,我经常要用到通过prototype扩展了MovieClip的方法inputStr和clearStr来做数字输入,但是默认的MovieClip类的代码提示中显然是没有这两个方法的;还有就是经常用到的动态为MovieClip添加的属性_xx、_yy、_d等,我也希望它们能出现在代码提示中。另外一个是自己的写的类或者是含有属性、方法的常用Object对象等,都希望它能出现在代码提示中。
[问题分析]:
归纳问题描述,可以知道需要从两方面入手,一是如何为已有类增加一些提示,而是如何添加自定义类的代码提示。
[解决问题]:
1、第一个问题,其实默认类的代码提示都是用Xml文件保存的,我们只需要找到这个文件,做些修改就可以了。以FlashMX2004为例,在C:\Documents and Settings\当前用户\Local Settings\Application Data\Macromedia\Flash MX 2004\软件语言\Configuration\ActionsPanel目录下找到ActionsPanel.xml,用你喜欢的XML文件编辑软件(我用的是Macromedia Dreamweaver 8)打开它,我们知道attachMovie是MovieClip类的默认方法,所以我们搜索attachMovie,找到位置后,就可以在它后面添加我们的方法,比如我要添加inputStr和clearStr方法,就可以这样输入:
同样,先查找_x,然后添加我们的_xx、_yy、_d等,此处就不说了。
2、我们知道this关键字在代码中表示的意义不同,有时表示MovieClip有时表示声音对象,等等其他,所以Action中的代码提示并未给this指定如何提示代码,但是我经常用this表示MovieClip类,所以希望键入this.的时候能出现MovieClip类的相关信息。打开同一个目录下的AsCodeHints.xml,在里面添加
即可。当然,你也可以添加你自己喜欢的提示。
3、关于自定义类的代码提示,Flash中提供了一个 CustomActions类用来在Flash开发工具中注册和卸载自定义类的代码提示,你可以看下这个介绍。不过我不愿意使用它,比较麻烦,还是直接往里面添加比较好。打开目录C:\Documents and Settings\当前用户\Local Settings\Application Data\Macromedia\Flash MX 2004\软件语言\Configuration\ActionsPanel\CustomActions,这个目录就是用来放自定义类的代码提示的,我想为自定义的SoundCtrl类添加代码提示,于是就创建一个名为SoundCtrl.xml的文件,里面的内容如下:
,这样在Action面板中只要输入任何以_sdCtrl结尾的名字,然后再键入.时就会出现这些提示了。
另:虽然这是添加自定义类代码提示的方法,其实就算不是类,依然可以这样添加,比如我经常写playObj的Object来控制播放暂停,它并未定义成一个class,它有play、pause、stop的方法,还有startLabel的属性,依然可以用为class添加代码提示的方法为它添加提示:
[小结]就写这些吧。另外需要注意的是编码格式要为utf-8.
名字空间使你能够控制你创建的属性和行为的可见性。public, private, protected, and internal 这些访问控制符都是内置的名字空间.如何这些预定义的访问控制符不能满足你的需求,你就可以定义自己的名字空间.
如果你熟悉XML的名字空间的话,那么这里的一些讨论对你来说都不会陌生,当然,语法和细节方面,ActionScript实现起来和XML还是有些细微的差别 的. 如果你之前从未接触过名字空间, 概念本身是很简单的,但是你仍然需要仔细学习下使用细节.
首先要知道,一个属性或者行为的名字总是包括两部分:标识符和名字空间. 标识符就是平常认为的名字. 比如,在下面的类定义中标识符就是 sampleGreeting 和 sampleFunction():
class SampleCode
{
var sampleGreeting:String;
function sampleFunction () {
trace(sampleGreeting + " from sampleFunction()");
}
}
只要没有为定义加上名字空间属性, 它们的名字都默认属于 internal 名字空间, 也就是说它们只对位于同一个包内的调用者可见. 如果设置编译器为严格模式, 编译器会对没有指定名字空间属性的标识符给出警告. 为了确保一个标识符在任何地方都可用,你必须在标识符前加上public 属性. 在前面的例子中sampleGreeting 和sampleFunction() 都有internal名字空间属性.
使用名字空间可以按照如下的三步. 首先, 你必须使用namespace 关键字定义一个名字空间. 比如, 下面定义了一个名为 version1 的名字空间:
namespace version1;
其次, 在声明一个属性或者行为的时候使用你定义的名字空间替换访问控制符. 下面的例子把名为 myFunction() 的函数放入 version1 名字空间中:
version1 function myFunction() {}
第三, 一旦你使用了名字空间, 你可以直接使用use 引用它或者通过名字空间限定标识符. 下面的例子通过直接使用use引用myFunction() 函数:
use namespace version1; myFunction();
你也可以像下面的例子这样,使用一个限定的名字引用myFunction() 函数:
version1::myFunction();
名字空间包括一个统一资源标识符(URI)的值, 也就是有时被称为名字空间的名字. URI 使你能够确保你的名字空间定义是唯一的.
有两种方法可以实现通过声明一个名字空间的定义来创建名字空间. 你可以像定义XML的名字空间一样,使用一个确定的URI来定义名字空间, 或者你也可以忽略URI. 下面的例子展示了如何通过使用URI定义名字空间:
namespace flash_proxy = "http://www.adobe.com/flash/proxy";
这个URI使用一个唯一的字符串表示. 如果你像下面的例子一样忽略URI,编译器会为这个URI创建一个唯一、内在的的字符串标识. 但是你没有访问这个内在字符串标识的权限.
namespace flash_proxy;
不管是使用URI还是不使用URI,一旦你定义了一个名字空间,就不能在相同的范围内再次定义这个名字空间. 试图定义一个在相同范围内已经定义好的名字空间会导致一个编译期错误.
如果名字空间是在包或者类内部定义的, 那么它对包或者类外部的代码一般是不可见的,除非使用适当的访问控制符.下面的代码展示了在包flash.utils内定义名字空间 flash_proxy . 下面的例子中没有访问控制符,也就是说,名字空间flash_proxy只对flash.utils包内的代码可见,对该包外的所有代码不可见:
package flash.utils
{
namespace flash_proxy;
}
下面的例子使用 public 属性使得名字空间 flash_proxy 对包外的所有代码可见:
package flash.utils
{
public namespace flash_proxy;
}
应用名字空间也就是把一个定义放到名字空间里面. 可以放到名字空间里面的定义包括函数、变量和常量(不能把类放到自定义的名字空间里面).
考虑一个使用public 访问控制名字空间声明的函数. 在函数定义中使用public 属性会把函数放到public名字空间中, 从而使该函数对所有代码可用. 一旦你自定义了一个名字空间你可以像使用public属性一样使用这个名字空间, 同样,名字空间中的定义会对所有可以访问这个自定义的名字空间的代码可用. 比如, 假设你定义了一个名为 example1的名字空间, 你可以使用example1作为属性把名为myFunction() 的函数添加进来, 如下所示:
namespace example1;
class someClass
{
example1 myFunction() {}
}
使用名字空间example1作为属性声明函数myFunction() 意思是该函数属于名字空间example1.
当应用名字空间的是有你应该记住下面几点:
public, private, protected, or internal .当使用一个用访问控制名字空间,比如public, private, protected, and internal,声明的方法时,没有必要明确引用这个名字空间. 这是因为对这些特殊名字空间的访问由上下文来控制. 比如,放入到private名字空间中的定义自动对同一个类中的代码可用. 但是对你自定义的名字空间,这种上下文制约并不存在. 为了使用已经放入到自定义名字空间中的方法或者属性,你必须引用这个名字空间.
你可以直接使用use namespace引用名字空间,或者你可以使用名字空间加名字限定词(::)限定名字. 通过直接使用use namespace引用名字空间将 “打开” 该名字空间,然后它就可以应用到所有还未被限定的标识符. 比如,如果你已经定义了名字空间example1 ,你可以通过使用use namespace example1访问该名字空间中的名字:
use namespace example1; myFunction();
同一时间你可以打开多个名字空间. 一旦使用use namespace打开了名字空间, 它将在被打开的代码块范围内始终保持打开状态. 没有办法显式的关闭一个名字空间.
但是多个打卡的名字空间会增加名字冲突的可能. 如果你不希望打开一个名字空间,你可以使用名字空间加::限定方法或者属性名字的办法替代直接使用 use namespace . 比如,下面的代码展示了如何使用名字空间example1限定函数myFunction():
example1::myFunction();
Flash Player API中的Flash.utils.Proxy类就是使用名字空间避免名字冲突的例子.Proxy类, 是ActionScript 2.0中的Object.__resolve属性的替代者, 允许在发生错误前中断对未定义属性或方法的引用. Proxy类的所有方法位于 flash_proxy名字空间中来避免命名冲突.
为了更好的理解flash_proxy名字空间是如何作用的, 首先要知道如何使用Proxy类. 只有继承自Proxy的类才能使用Proxy类的功能.换句话说, 如果想在一个对象上使用Proxy类的方法,那么这个对象的定义必须扩展Proxy类. 比如,如果想中断调用未定义方法的尝试, 你需要扩展Proxy类并且重写Proxy类的callProperty() 方法.
回想一下实现名字空间的3个步骤:定义、应用和引用名字空间. 但是,名字空间flash_proxy只是被定义、应用,却从未被引用过,这是因为我们从来没有明确的调用过Proxy类的任何方法. Flash Player API 在Proxy类的内部定义和应用名字空间 flash_proxy. 你的代码只需要对扩展自Proxy的类应用名字空间flash_proxy.
名字空间flash_proxy 定义在包flash.utils内,就像下面这样:
package flash.utils
{
public namespace flash_proxy;
}
下面这段摘自Proxy类的代码,展示了名字空间如何应用到Proxy类的方法上:
public class Proxy
{
flash_proxy function callProperty(name:*, ... rest):*
flash_proxy function deleteProperty(name:*):Boolean
...
}
像下面这段代码所展示的,你必须首先导入Proxy类和名字空间flash_proxy. 接下来还必须声明你的类是扩展自Proxy类(如果是在严格模式下编译,必须添加dynamic属性). 当你重写callProperty()方法的时候,必须使用名字空间flash_proxy做限定.
package
{
import flash.utils.Proxy;
import flash.utils.flash_proxy; dynamic class MyProxy extends Proxy
{
flash_proxy override function callProperty(name:*, ...rest):*
{
trace("method call intercepted: " + name);
}
}
}
如果你创建了MyProxy类的实例,并且尝试调用一个未定义的方法,比如像下面例子中调用testing()方法,你的Proxy对象会终止这个调用,并且执行复写的方法callProperty()内的语句(在这里就是执行一个简单的 trace() 语句).
var mySample:MyProxy = new MyProxy(); mySample.testing(); // method call intercepted: testing
将Proxy类的方法放在flash_proxy名字空间中有两个优点.首先, 拥有一个独立的名字空间减少了从类Proxy扩展的类的公共接口的混乱. (类Proxy中有大约一打的方法可以被重写,这些方法不是设计成能直接调用的. 把它们都放在公共名字空间中会产生混淆.) 其次,如果你的Proxy子类的实例方法和Proxy类的方法名字相同时,使用名字空间flash_proxy可以避免这种情况下的命名冲突. 比如,你可能想把你自己的一个方法命名为callProperty(). 下面的代码是允许的,因为callProperty()在不同的名字空间中:
dynamic class MyProxy extends Proxy
{
public function callProperty() {}
flash_proxy override function callProperty(name:*, ...rest):*
{
trace("method call intercepted: " + name);
}
}
当使用4种访问控制符(public, private, internal, and protected)不能满足需求时,使用名字空间会很有用. 比如, 你可能拥有一些很有用的方法,但是这些方法被放在了不同的包中. 你想让这些方法对所有的包可用,但是又不想让这些方法成为public的. 在这种情况下,你可以创建一些名字空间,然后用它作为你自己的防伪控制符来达到访问控制的目标.
下面的例子使用用户定义的名字空间把两个位于不同包中的函数组合在一些. 通过把它们组合在相同的名字空间中,就可以使用use namespace语句使它们对类或者包可见.
这个例子使用4个文件演示这种技术. 所有的文件都必须位于类路径中. 第一个文件, myInternal.as, 用来定义名字空间myInternal. 因为这个文件位于名为example的包内,所以你必须把这个文件放到名为example的文件夹内. 这个名字空间被标记为public,因此,它可以被导入到任何包内.
// myInternal.as in folder example
package example
{
public namespace myInternal = "http://www.adobe.com/2006/actionscript/examples";
}
第2个和第3个文件, Utility.as and Helper.as, 定义了类,类中包含应该被其他包可用的方法.Utility类在example.alpha包中,也就是说,这个文件应该放在example文件夹内的alpha子文件夹内. Helper类位于example.beta包中,这个文件应该放在example文件夹内的beta子文件夹内.所有这些包, 包括example.alphaexample.alpha 和 example.beta, 都必须首先import名字空间后再使用它.
// Utility.as in the example/alpha folder
package example.alpha
{
import example.myInternal;
public class Utility
{
private static var _taskCounter:int = 0;
public static function someTask()
{
_taskCounter++;
}
myInternal static function get taskCounter():int
{
return _taskCounter;
}
}
}
// Helper.as in the example/beta folder
package example.beta
{
import example.myInternal;
public class Helper
{
private static var _timeStamp:Date;
public static function someTask()
{
_timeStamp = new Date();
}
myInternal static function get lastCalled():Date
{
return _timeStamp;
}
}
}
第4个文件, NamespaceUseCase.as, 是主应用类, 应该放到example文件夹内.在Adobe Flash CS3 Professional中, 这些类应该当作FLA的文档类使用. NamespaceUseCase类同样导入了名字空间myInternal,然后使用它调用位于其他包中的两个静态方法.这个例子使用静态方法只是为了使代码简单.静态方法和实例方法都可以放入名字空间myInternal 中.
// NamespaceUseCase.as
package
{
import flash.display.MovieClip;
import example.myInternal; // import namespace
import example.alpha.Utility; // import Utility class
import example.beta.Helper; // import Helper class
public class NamespaceUseCase extends MovieClip
{
public function NamespaceUseCase()
{
use namespace myInternal;
Utility.someTask();
Utility.someTask();
trace(Utility.taskCounter); // 2
Helper.someTask();
trace(Helper.lastCalled); // [time someTask() was last called]
}
}
}
今天装上了Adobe Flash CS3 Professional30天试用版,迫不及待的看了下它的ActionScript编辑面板,果然没有让我失望,添加了一些实用功能。如下图
收缩选中的代码(按下ALT键可以收缩未选中的代码)
展开所有代码
添加注释块:
添加行注释:
移除注释:
OK,实验下功能如何,首先试下收缩代码功能,如下图状态下点击收缩代码(注意光标位置):
效果如下
我们看到test函数里的代码收缩了。
我们把光标移到test函数里的for循环里面去,如图:
效果如图:
两者对比,就应该明白它的作用了。好了,接下来看看收缩选定代码段的功能:
收缩选中代码的效果:
在按下收缩选中代码的同时我们按下ALT键,则是收缩未选中的代码:
我们把用鼠标点击每行行号的位置会出现图示:
点击后如下图
也就是说原本用来插入断点的位置被用来收缩代码用了,那么如何插入断点呢?答案是在顶端的工具中有:
哈哈,不错吧,以后不会应为大括号太多而看花眼了。
接下来看看注释功能:分块注释和行注释,以及移除注释。
试了下发现,移除注释并不会移除注释的内容,只是把块注释的/**/和行注释的//去掉,如下图:
效果为:
好了,就这些了。总的来说,比之前的是有了大大的提高了。

JSEclipse是在Eclipse环境下快速、无错开发JavaScript的插件。使用JSEclipse,你可以完成从编辑小段代码到使用大的AJAX库或者为内置了JavaScript片段的产品开发插件的各种不同任务。
下载、安装JSEclipse、改善你的JavaScript代码编辑体验:
之前一直用z-blog,现在想换个写写,有些喜新厌旧呵呵。原来的z-blog还保留着,说不定那天还会回去写。
You are currently browsing the 技术·人生 weblog archives for 4月, 2007.
