日期:2014-05-16  浏览次数:20401 次

JS 与 AS 交互及效率对比

?

? ? 想象下有这样的业务场景,我用flash实现了文件的上传,上传完之后,我们可能需要在页面上弹个提示框告诉用户上传结果。我们不可能把所有东西都放在flash里完成,因为那样flash的文件会加大,而且也不够灵活,因为flash是需要编译后才能跑的,所以我们最好把能用js实现的都剥离出来,让flash只做一些核心的功能。这样,我们就需要用as去调用js。同样的,如果js操作完了想通知到flash,就需要用js去调用flash中的as方法。此时可以看作as是js增强的一部分。

???? 不管是as调用js,还是js调用as,其实都围绕ExternalInterface。ExternalInterface 类是外部 API,这是一个在 ActionScript 和 Flash Player 容器之间实现直接通信的应用程序编程接口。当然插入flash的html标签中<param name='allowScriptAccess' value ='always' /> 不能为never,如果设置成never一下所有都是空谈了,一般情况下都设置成always,它也可以接受具体的domain或者IP。

???? ExternalInterface有两个提供相互调用的静态方法:
     /**
      * @param functionName {String} 
      * @param closure {Function}
      * @usage 将 ActionScript 方法注册为可提供外部js调用。
      */
     addCallback(functionName:String, closure:Function):void 

     /**
      * @param functionName {String} 
      * @param arguments {Function} (optional)
      * @usage 调用页面上的js。
      */
     call(functionName:String, ... arguments):*
?

Example 1:
假如页面上有一个叫sayHi的js函数, 如下:
window.onload=function (){
     function sayHi(){alert('Hello JS')}
}
?
要在flash中调用这个函数,可以用两个办法:
navigateToURL(new URLRequest( 'javascript:sayHi()' ), '_self'); //实际上打开一个新窗口,只不过url是javascript:sayHi(),这是土鳖方法
ExternalInterface.call( 'sayHi');// 用到了ExternalInterface类,这种方法也是adobe推荐的做法
?
运行结果,发现两个都没法执行,这是因为flashplayer只能看到页面上全局的javascript,所以要想能让flash拿到这个js函数,必须暴露出来。修改代码在运行
window.onload=function (){
     function sayHi(){alert('Hello JS')}
     window['sayHi'] = sayHi;
}
?
代码成功运行了,于是,我们可以总结出一点:提供给flash调用的js函数必须是全局的,获取寄宿在全局对象上的。
? ? ?有时候我们只用到了flash的功能,而没用到它的UI所以想把flash隐藏,比如做一个即时通讯的东西,只有通讯部分用到了flash, 当尝试把flash设置成display:none的时候,发现js与as根本无法相互调用,所以说如果需要隐藏flash,设置css是行不通的,可以设置它的宽高为1px来解决。

???? 如果是想在js中调用as方法,需要用ExternalInterface.addCallback注册as方法,让他暴露在flash实例上。比如flash中有这样的方法:
private function sayHi():void{
     Alert.show('Hi As');
}
External.addCallback('jsSayHi', sayHi);
?
这样就可以在js中执行jsSayHi这个代理方法,它会去执行sayHi这个as方法。jsSayHi这个代理方法会寄宿在flash dom元素上,作为dom元素的方法。
window.onload=function (){
     document.getElementById('flashId').sayHi();
}
?
测试一下,还是发现了问题,有时候能正常运行,但有时候会抛出错误:Uncaught TypeError: Object #<HTMLObjectElement> has no method 'jsSayHi',这是因为即使当前页面onload了,但是flash中的代码初始化还没运行完,所以还没有把代理方法注册到flash dom元素上。(查看实例3-jscallas_b.html)

???? 那么,flash有没有类似domready的时间点呢?查看好多资料没看到,但是可以模拟一个。我们认识当flash能正常调用页面上的js时,flash能正常跟js进行交互。我们在页面上定义一个flashready函数,让flash回调。
function flashready(){
     document.getElementById('flashId').jsSayHi(); 
     alert('flash is ready');    
}
?

ExternalInterface.call( 'flashready' );
?

? ? ?这样js对as的调用就能100%的成功了。

? ? ?对于静态资源往往会放在cdn上,比如有一台cdn域名是cdn.com,而主域名确是xxx.com,这样就出现了跨域的问题。浏览器的安全策略导致ajax不能正常的跨域请求,flash p