一.JavaScript調用ActionScript公開的方法
在Flex中通過ExternalInterface調用addCallback()來將AS的一個方法註冊為一個JS和VBScript可以調用的方法。
函數如下:
addCallback(function_name:String, closure:Function):void
function_name就是Flex對外部展示,能夠被JS調用的函數。
closure是Flex中AS寫的函數
as:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete="initApp()">
<mx:Script>
<![CDATA[
import flash.external.*; //引入ExternalInterface
public function myAsFuncn(js:String):String
{
return "js:"+js+"訪問了 as:"+asInput.text;
}
public function initApp(): void{
ExternalInterface.addCallback("myAsFuncn",myAsFuncn);
}
]]>
</mx:Script>
<mx:TextInput id="asInput"/>
</mx:Application>
js:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="UTF-8">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta http-equiv="Content-Language" content="UTF-8" />
<head>
<script src="swfobject.js" type="text/javascript"></script>
<script src="jquery.js" type="text/javascript"></script>
<script type="text/javascript" >
//var swf = new swfobject("FlexDemo003.swf", "myFlexFun", "300px", "200px", "9.0.0","expressInstall.swf", flashvars,params);
//swf.write("myFlexFun");
var flashvars = {};
var params = {menu: "false",wmode:"opaque"};
swfobject.embedSWF("FlexDemo003.swf", "myFlexFun", "300px", "200px", "9.0.0","expressInstall.swf", flashvars,params);
function callAs()
{
var myFlexfun = findSWF("myFlexFun");
var result = myFlexfun.myAsFuncn("點我看效果按鈕");
alert(result);
}
function findSWF(movieName) {
if (navigator.appName.indexOf("Microsoft")!= -1) {
return window[movieName];
} else {
return document[movieName];
}
}
</script>
</head>
<body>
<div id="myFlexFun"></div>
<input type="button" value=" 點我看效果" onclick="callAs()" />
</body>
</html>
二.ActionScript調用JavaScript方法
call(ExternalInterface.call 方法)
public static call(methodName:String, [parameter1:Object]) : Object
參數
methodName:String ― 要在容器中調用的函數的名稱。如果該函數接受參數,則這些參數必須顯示在 methodName 參數後面。
parameter1:Object [可選] ― 要傳遞到該函數的任何參數。您可以指定零個或多個參數,參數之間用逗號分隔。此參數可以是任何 ActionScript 數據類型。當調用 JavaScript 函數時,ActionScript 類型自動封裝到 JavaScript 類型中。當調用某個其它 ActiveX 容器時,將在請求消息中對參數進行編碼。
返回
Object ― 從容器接收的響應。如果調用失敗(例如,當容器中沒有這種函數時、接口不可用時、發生遞歸時,或出現安全問題時),則返回 null。
js:
<html>
<head>
<script language="JavaScript" type="text/javascript">
//無參數
function myJsFunctionNoPara() {
alert("as 調用 js了");
}
//有參數
function myJsFunctionHavePara(p) {
alert(p);
}
</script>
</head>
<body>
<object id="myFlexFun" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,29,0"
width="250" height="300">
<param name="movie" value="AS2JS.swf" />
<param name="quality" value="high" />
<embed src="AS2JS.swf" quality="high" pluginspage="http://www.macromedia.com/go/getflashplayer"
type="application/x-shockwave-flash" width="250" height="300"></embed>
</object>
</body>
</html>
as:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
private function callNoParaJavaScript():void {
ExternalInterface.call("myJsFunctionNoPara");
}
private function callHaveParaJavaScript():void {
ExternalInterface.call("myJsFunctionHavePara","as 調用js了");
}
]]>
</mx:Script>
<mx:Button label=" 調用無參數js:Say 'as 調用js了'" click="callNoParaJavaScript();" />
<mx:Button label="調用有參數js:Say 'as 調用js了'" click="callHaveParaJavaScript();" />
</mx:Application>
3.調用內置js函數
ExternalInterface.call("alert", "Hello World, from ActionScript");
ExternalInterface.call("eval", "alert('OK')");
三.常見問題
1.ExternalInterface.addCallback參數
JavaScript 跟 ActionScript 3.0 交互也是通過 flash.external.ExternalInterface 這個類,不過與跟 Flash 8 中跟 ActionScript 2.0 交互所使用的 flash.external.ExternalInterface 還是有所不同的。最大的不同就是 ExternalInterface.addCallback 方法在 ActionScript 3.0 中只有 2 個參數了,而不再有 instance 這個參數。
2.avaScript 調用 Flash 中的 ActionScript3.0提示方法不存在
這個問題是跟 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 的操作,直接運行就可以了。通過這種方法把這些任務封裝後,使用這些封裝之後的操作,在編寫代碼就可以按照順序(而不是異步)來寫了,執行時也是順序執行啦。
3. 在IE中用JavaScript 動態創建的 Flash 標籤的問題
如果你是通過 JavaScript 動態創建的 Flash 標籤然後插入到 html 中的話(例如通過 innerHTML 賦值的方法或者 appendChild 的方法),很可能你這個操作是在 window.onload 之後才進行,在這種情況下,其它瀏覽器可以正常進行 JavaScript 和 ActionScript 3.0 的交互,IE 就不行。所以,為了保險,最好的方法就是直接把 flash 標籤的 html 寫在 html 的 body 中,或者用 JavaScript 的 document.write 來寫入 html 的 body 中,後面這種方法對於 IE 來説更合適一些,因為這樣的話,可以不需要點擊激活 Flash。
4. 在IE中 as發佈方法名問題
不要在 ActionScript 3.0中發佈名字為 invoke 的方法,否則在 IE 中,JavaScript 調用該方法時會出錯。
5.在ie中flash在form的位置
不要把 flash 放到 form 中,否則在 IE 中,JavaScript 調用 ActionScript 時會出錯。當然,網上也給出了一個解決這個問題的腳本,不過那個貌似是針對 Flash 8 的 ActionScript 2.0 的,我沒有試過,不知道對
ActionScript 3.0 是否同樣有效。
6.方法參數包含轉移符號的問題
如果在 ActionScript 中通過 ExternalInterface.call 調用 JavaScript 時,參數中如果含有轉義字符(\)和特殊字符(\n,\r等)就可能出錯。因為在ActionScript和JavaScript中都將“\”作為轉義字符,這裏的”\\”在程序執行時實際上就是一個[\].
解決辦法1:如要傳遞的數據是 data,將它進行一次 data.replace(/\\/, “\\\\”) 替換之後,在傳遞給 JavaScript 就可以了。
解決辦法2:js和as中有現成的兩個全局函數:escape()和unescape()。在調用函數和函數返回前escape一下,接收到參數和函數返回值後再unescape一下就可以了。
as:
var str:String = "\n\r123\\abc";
str = escape(str); // encode
var jsret:Object = ExternalInterface.call("jsfun", str);
if (jsret is String) {
jsret = unescape(jsret as String); // decode
Alert.show(jsret.toString());
}
js:
function jsfun(str) {
str = unescape(str); // decode
str += "from js";
str = escape(str); // encode
return str;
}