浏览模式: 标准 | 列表

这两天做基于 Flash9(ActionScript 3.0)的 JavaScript PHPRPC 3.0 客户端时遇到了一些 JavaScript 与 ActionScript 3.0 交互的一些问题,这些问题在网上基本上都没有找到答案,最后通过不断的尝试才得以解决,因此在这里总结出来,希望能给遇到同样问题的同志们一些帮助。

JavaScript 跟 ActionScript 3.0 交互也是通过 flash.external.ExternalInterface 这个类,不过与跟 Flash 8 中跟 ActionScript 2.0 交互所使用的 flash.external.ExternalInterface 还是有所不同的。最大的不同就是 ExternalInterface.addCallback 方法在 ActionScript 3.0 中只有 2 个参数了,而不再有 instance 这个参数。下面要讨论的这些问题都是关于 Flash 9 中 ActionScript 3.0 的。

先来说最常遇到的问题,就是在 JavaScript 调用 Flash 中的 ActionScript 方法时报告该方法不存在。这个问题是跟 Flash 中执行 ExternalInterface.addCallback 的时间有关的,ExternalInterface.addCallback 必须要在 HTML 的完全载入之后也就是 window.onload 事件执行后才可以执行,否则,它所发布的方法都无法在 JavaScript 中调用。

解决这个问题的方法在 Flash 9 的 ActionScript 3.0 帮助中有个例子,里面包含了这个解决方法,就是首先在 js 中设置两个标志,例如 jsReady 和 swfReady 这两个变量作为标志,开始都设置为 false,当 window.onload 时,设置 jsReady 为 true,在 Flash 中一开始检查 JavaScript 中的这个 jsReady 标志是否是 true(通过 ExternalInterface.call 方法调用 JavaScript 中的返回这个标志的一个函数),如果不为 true,就设置一个定时器,经过一段时间后(例如 50 或 100 毫秒)重复这个检查这个标志,一旦为 true,则执行 ExternalInterface.addCallback 来发布 ActionScript 要提供给 JavaScript 调用的函数或方法,执行完所有的 ExternalInterface.addCallback 后,通过 ExternalInterface.call 方法调用 JavaScript 中的设置 swfReady 标志的函数设置 swfReady 为 true。之后,当 JavaScript 检测到 swfReady 为 true 后,再调用 ActionScript 中的方法就不会遇到上的说的这个问题了。

如果简单一点的调用这样还可以,如果是有好多这样的调用就比较麻烦了。我是通过建立两个执行队列:jsTaskQueue 和 swfTaskQueue,当在 jsReady 为 true 之前,如果有要调用 ActionScript 的操作,就把这个操作放到 jsTaskQueue 中,当 js 在 window.onload 中执行设置 jsReady 时,把这个队列中的任务取出来执行,当 jsReady 为 true 后 swfReady 为 true 之前,如果有要调用 ActionScript 的操作,就把这个操作放到 swfTaskQueue 中,当 ActionScript 通过 ExternalInterface.call 方法调用 JavaScript 中的设置 swfReady 标志的函数设置 swfReady 为 true 时,把这个队列中的任务取出来执行。当 jsReady 和 swfReady 都为 true 时,那么如果有要调用 ActionScript 的操作,直接运行就可以了。通过这种方法把这些任务封装后,使用这些封装之后的操作,在编写代码就可以按照顺序(而不是异步)来写了,执行时也是顺序执行啦。

除了这个最常遇到的问题之外,还有两个关于 IE 上的问题。

如果你是通过 JavaScript 动态创建的 Flash 标签然后插入到 html 中的话(例如通过 innerHTML 赋值的方法或者 appendChild 的方法),很可能你这个操作是在 window.onload 之后才进行,在这种情况下,其它浏览器可以正常进行 JavaScript 和 ActionScript 3.0 的交互,IE 就不行。所以,为了保险,最好的方法就是直接把 flash 标签的 html 写在 html 的 body 中,或者用 JavaScript 的 document.write 来写入 html 的 body 中,后面这种方法对于 IE 来说更合适一些,因为这样的话,可以不需要点击激活 Flash。

另一个问题是,不要在 ActionScript 中发布名字为 invoke 的方法,否则在 IE 中,JavaScript 调用该方法时会出错。

最后一个问题,网上可以查到的比较多了,就是不要把 flash 放到 form 中,否则在 IE 中,JavaScript 调用 ActionScript 时会出错。当然,网上也给出了一个解决这个问题的脚本,不过那个貌似是针对 Flash 8 的 ActionScript 2.0 的,我没有试过,不知道对 ActionScript 3.0 是否同样有效。


11 月 23 日补充:

今天又发现一个问题,如果在 ActionScript 中通过 ExternalInterface.call 调用 JavaScript 时,如果传递的参数有字符串,那么字符串中如果包含 \ 符号的话,那么将会调用失败。这个也是 ActionScript 和 JavaScript 交互的一个 bug,解决办法是,对传递的字符串先进行一下处理在传递,处理方法很简单,比如要传递的数据是 data,将它进行一次 data.replace(/\\/, “\\\\”) 替换之后,在传递给 JavaScript 就可以了。

» 阅读全文

constructor PHPRPC_Client();
constructor PHPRPC_Client(string serverURL);
constructor PHPRPC_Client(string serverURL, array functions);
constructor PHPRPC_Client.create();
constructor PHPRPC_Client.create(string serverURL);
constructor PHPRPC_Client.create(string serverURL, array functions);

Create PHPRPC Client object. The username and password can be contained in serverURL for HTTP Basic Authorization, but it is NOT recommended (see also useService method for the recommended usage). To use create method create PHPRPC Client object in VBScript.

If you hope that the PHPRPC Client initialize remote functions without connecting to the PHPRPC Server, you can use the parameter functions.

useService(string serverURL);
useService(string serverURL, string username, string password);
useService(string serverURL, string username, string password, array functions);

Set the URL of the PHPRPC Server. The username and password can be contained in serverURL for HTTP Basic Authorization, but it is NOT recommended. It is recommended to specify the username and password by parameters.

If you hope that the PHPRPC Client initialize remote functions without connecting to the PHPRPC Server, you can use the parameter functions.

boolean setKeyLength(int keyLength);

Set the key length for the key exchange. This method will return false when the key exchange already to be done.

int getKeyLength();

Get the key length. This method will return actual value when the key exchange being done. Otherwise, you will get the default length or which length you set.

boolean setEncryptMode(int encryptMode);

Set the encrypt mode. 0 denotes no encrypting any data. 1 denotes encrypting arguments in the transfer. 2 denotes encrypting arguments and result. 3 denotes encrypting arguments, result and output of the server console. Set other value, it would return false.

int getEncryptMode();

Get the encrypt mode.

string remoteFunctionName(arg1, arg2, ..., argN);
string remoteFunctionName(arg1, arg2, ..., argN, callbackFunction);
string remoteFunctionName(arg1, arg2, ..., argN, callbackFunction, byRef);

Invoke the server function directly. The return value is remoteFunctionID, you can use abort method to abort the remoteFunction with this value. You can specify a callbackFunction, when the remote function completed, this callbackFunction will be call automatically. If you want to transfer the arguments by reference, set byRef to be true. If you didn’t specify a callbackFunction, the default callback function is remoteFunctionName_callback(), You can define it separately. the callbackFunction can be defined like this:

callbackFunction = function (result, args, output, warning) {
   ...
}

The parameter result is the remote function result, when an error occurred during invoking remote function, this parameter is a PHPRPC_Error object. The parameter args is the remote function arguments, you can get the changed arguments with it when transfering the arguments by reference. The parameter output is the output of the server console after invoke the remote function. The parameter warning is the warning of the server function after invoke the remote function, it is a PHPRPC_Error object.

onready();

This is a event. When the useService method completes, this event will be fired.

boolean getReady();

When the useService method completes, this method return true, otherwise return false.

string invoke(remoteFunctionName, arg1, arg2, ..., argN);
string invoke(remoteFunctionName, arg1, arg2, ..., argN, callbackFunction);
string invoke(remoteFunctionName, arg1, arg2, ..., argN, callbackFunction, byRef);

This method is similar to remoteFunctionName in calling remote function. The difference is the invoke method is available before the ready property becomes true, that is to say, this method can be called immediately after using useService method.

abort();
abort(string remoteFunctionID);

If you used this method without parameter, it would stop all of the remote functions. If you specified the remoteFunctionID, it would only stop the remote function you specified.

setTimeout(int timeout);

Set the timeout of the invoking of the remote function. the timeout is the number of milliseconds. Default value is 30 seconds. If you want to disable timeout, set timeout to 0 or null.

int getTimeout();

Get the timeout of the invoking the remote function. the return value is the number of milliseconds.

constructor PHPRPC_Error(int errno, string errstr);

You never need to create PHPRPC_Error object by yourself, when an error occurred during invoking remote function, this object will be created automatically as the result of callback function.

int getNumber();

return error number.

string getMessage();

return error message.

string toString();

return a string which include the error number and error message.

» 阅读全文

前面我们讨论了如何在 JavaScript 语言中实现对私有实例成员、公有实例成员、私有静态成员、公有静态成员和静态类的封装。这次我们来讨论一下面向对象程序设计中的另外两个要素:继承与多态。 本次讨论中,主要涉及到定义和赋值,this 和执行上下文,原型继承和调用继承,以及重载和覆盖这么几个方面的内容。

» 阅读全文

JavaScript 是一种非常灵活的面向对象程序设计语言,它与传统的强类型的面向对象程序设计语言(如 C++,Java,C# 等)有很大不同,所以要实现如 C++、java、C# 当中的一些特性就需要换一种思考方式来解决。今天主要讨论如何在 JavaScript 脚本中实现数据的封装(encapsulation)。

数据封装说的简单点就是把不希望调用者看见的内容隐藏起来。它是面向对象程序设计的三要素之首,其它两个是继承和多态,关于它们的内容在后面再讨论。

本文主要讨论的是在 JavaScript 面向对象程序设计中,对私有实例成员、公有实例成员、公有静态成员、私有静态成员和静态类的封装办法。

» 阅读全文

http://www.hedgerwow.com/360/dhtml/text-overflow.php 找到的好东西,这个是兼容 IE 和 Firefox 的,稍加修改,就兼容 Opera 了。现在已经应用到 extmail 中了,效果很不错。

下载:text-overflow.zip

» 阅读全文