flex与js通信与彼此之间的互调整理(二)

之前写了一篇flex和js之间的通信,还记得最开始研究这两门语言如何交互,一晃我的任务也快做完了,公司的realspace产品之开了js的API,但是现在使用flex产品的人也比较多,要求开设flex的三维API,已经过去几个月了,产品也上线了,有兴趣的可以在https://github.com/SuperMap/Flex-Realspace下载,这是一个利用as与js交互放在了一个完整的产品里。

网上也有很多关于flex和js通信的文章,不过不知道大家有没有注意到好像都需要把js文件放在固定的文件下(flex调用js),并且需要在index.template.html文件里面动手脚,而且你把源代码考给团队的其他人,发现flash builder导进去后重新生成了index.template.html,又得自己修改一下,不是很麻烦吗?如果你是需要此技术做自己的产品的话我建议你一定要看一下我想出的办法,也许会帮了不少人哦!

一个大项目或者产品,在js代码里面估计都会有很多用原型建的类,在flex端估计也有很多功能。我们的假设场景是你正在使用flex制作项目,不过有一些功能只能通过js来实现,所以你将部分功能使用js封装成了一些js的文件,希望通过as与js之间的通信来使用as语言调用js里面的功能。js文件基本已经写好了,但是因为需要在不少地方懂手脚团队协作起来不方便,我这篇文章就是用来解决这个问题的。

一、设计好代码

首先我们需要明白的是:js文件在启动之后被加载到html页面里面,我们可以通过ExternalInterface.call("js的方法",参数);在flex端调用js端的方法,我们可以通过ExternalInterface.addCallback("对外公开的方法名",具体实现的方法);来解决在js端调用flex端的方法。

现在我们需要思考:js里面有很多功能,我们每次调用js功能都得去调用相关的方法吗?那样as和js之间的耦合不是太高了,不符合设计模式,并且很麻烦。同样js这边需要回调(常用在事件回调上)flex的方法时,方法很多,我们是不是也要在flex端动态注册那么多个方法名称呢?那样不怕名称冲突吗?所以这样的实现都是不可取的。

为了达到低耦合,我将as和js之间的通信设定为只有两座桥,as调用js功能永远只会通过调用js里面的固定方法,js回调flex的功能也只能调用在程序初始化flex端动态创建的唯一的一个方法。这样as和js之间的通信永远只通过这两个方法来交互,就不会出现之前的很多问题。但是大家肯定想问如何知道我这一次调用的功能和我下一次调用的有什么区别怎么办?那就是在参数上面做手脚了。说白了就是通过参数来判断你的行为。

在我们flex realspace产品面as调用js的功能都是通过var result:Object=ExternalInterface.call("SuperMap.Web.Util.ApplicationManager.initBridgeFlexToJs",object);这一局来的,SuperMap.Web.Util.ApplicationManager.initBridgeFlexToJs是在js端的一个文件里面的方法,唯一的as访问js的通道,特殊的是object,这是一个键值对,形如:


代码如下:

var realArgument:Array=[strServerUrl.toString()+"$String"];
var array:Object={
action:"FUNCTION",
key:this.KEY,
functionName:"checkPluginUpdate",
isReturn:true,
realArgument:realArgument
};

上面的array就是我说的object,里面的action:"FUNCTION"代表我需要调用的是方法,调用的对象的key(唯一标示)是this.KEY,方法名称是checkPluginUpdate,有返回值,方法的参数是realArgument(一个特殊数组)。

其实这些有点类似json,用来传递数据的,而我自定义的一个格式是用来传递行为操作的,这个你们可以自己定义,反正核心就是通过参数来判断你的行为,方法永远调用同一个,这点明白了就是自己设计上的事情,不过在解析的时候有点麻烦哈!

二、打包js代码

如果你的代码符合我这样的逻辑,交互通过两座桥来通信,那么我们就开始下一步,其实这样设计后已经可以使得自己的产品交互起来很方便了,我当时花了一个月就是这么做的,都做的差不多了,上面交代说js代码不能开放出来,而且每次都需要修改index.template.html文件,太麻烦,希望flex端的开放人员完全看不到js的任何东西,要求需要把js文件打包成为swc文件,通过去调用swc文件里面的js来实现功能,我当时一听这简直就是不可能的嘛!不过后来研究了好久,发现这样可以实现,并且还有它的优势。

首先我们需要知道如何把js文件打包成为swc文件,新建一个库项目,将你的js文件都放进去,如下图:

我建的项目叫bridge,里面有我所有的js文件,还有不少as文件,细心的发现每一个js文件旁边都有一个...Stream.as文件,这里就是重点了,我们如何才能把js文件打包到swc里面呢,flex提供了一种流的方式,例如上面的ApplicationManager.js文件,我们创建一个类ApplicationManagerStream继承于flash.utils.ByteArray,代码如下:


代码如下:

package SuperMap.Js
{
import flash.utils.ByteArray;
/**
* 制定js文件以及打包方式
*/
[Embed(source="ApplicationManager.js", mimeType="application/octet-stream")]
public class ApplicationManagerStream extends ByteArray
{
public function ApplicationManagerStream()
{
super();
}
}
}

写好你对应的js文件,一定要和此类放在一个文件夹下,配上打包的类型application/octet-stream,每一个js文件都配置一个相应的as类,这样在

里面会自动生成好打包好的swc文件

现在问题又来了,里面是二进制的东西,我们如何使用啊,不是我们平时写的as类,写了什么方法引用这个包直接使用就行。

所以我们还需要一个as类。这里我创建IncludeStream.as,代码如下:


代码如下:

package SuperMap
{
import SuperMap.Js.ApplicationManagerStream;
import SuperMap.Js.HashTableStream;
import SuperMap.Js.SceneDivStream;
import SuperMap.lib_Ajax.IServerJava6RStream;
import SuperMap.lib_Ajax.JsStream;
import SuperMap.lib_Ajax.MicrosoftAjaxStream;
import SuperMap.lib_Realspace.RealspaceStream;
/**
* 此类主要用于以字符串形式获取二进制形式的js代码
*/
public class IncludeStream
{
/**
* 构造函数
*/
public function IncludeStream()
{
}
/**
* 返回js文件里面代码的字符串形式
*/
public function toString():String
{
var microsoftAjaxStream:MicrosoftAjaxStream=new MicrosoftAjaxStream();
var jsStream:JsStream=new JsStream();
var iServerJava6RStream:IServerJava6RStream=new IServerJava6RStream();
var realspaceStream:RealspaceStream=new RealspaceStream();
var hashTableStream:HashTableStream=new HashTableStream();
var applicationManagerStream:ApplicationManagerStream=new ApplicationManagerStream();
var sceneDivStream:SceneDivStream=new SceneDivStream();
return microsoftAjaxStream.toString()+jsStream.toString()+iServerJava6RStream.toString()+realspaceStream.toString()+hashTableStream.toString()+applicationManagerStream.toString()+sceneDivStream.toString();
}
}
}

有了这个类,我们可以通过实例化一个此对象,然后通过方法toString()获取到字符串形式的js的所有代码。这又是一个问题,我们还是不能使用,没法调用。不过先这样打包好,引用到你的flex项目里面再说。

三、调用js文件

首先我们要知道as调用js的方法只能调用js形式的方法,也就是嵌入到了html页面的js,而现在我们只有字符串形式的js源代码,所以需要想办法将它转化为标准的js代码,嵌入到html页面里面。

在你的flex项目启动的最开始的地方恰如如下代码:


代码如下:

//初始化一个字符串形式的方法parseStringToJs,用于将字符串转换为js语言
var str:String = "function parseStringToJs(str){var oHead = document.getElementsByTagName('HEAD').item(0);";
str+="var oScript = document.createElement(\"script\");";
str+="oScript.language = \"javascript\";";
str+="oScript.type = \"text/javascript\";";
str+="oScript.id = \"test\";";
str+="oScript.defer = true;";
str+="oScript.text = str;";
str+="oHead.appendChild(oScript);}";
//调用window.eval方法
ExternalInterface.call("eval",str);
var includeStream:IncludeStream=new IncludeStream();
//获取js的字符串形式的源代码
var strey:String=includeStream.toString();
//使用正则表达式修改字符串
var char:RegExp = /\\/g;
strey = strey.replace(char,"\\\\");
//生成js的API
ExternalInterface.call("parseStringToJs",strey);
//初始化js调用as的入口方法initBridgeJsToFlex,最终饭方法的实现转给方法ApplicationManager.initBridgeJsToFlex
ExternalInterface.addCallback("initBridgeJsToFlex",ApplicationManager.initBridgeJsToFlex);

注释已经写的很清楚了,不过正则表达式这一步可以不要,我这里是因为我的代码里出现了反斜杠的东西,所以我这样是为了转义一下,这里的思路就是先使用ExternalInterface.call去调用window对象的方法eval在window下创建一个将字符串转化为js代码的方法parseStringToJs,然后再调用此方法将我们的字符串的源代码进行转化,这样html中就存在js的代码了,就不用再去修改index.template.html文件添加引用和添加入口了。并且在其他地方你可以通过ExternalInterface.call直接调用js端公开的桥,并且通过ApplicationManager.initBridgeJsToFlex来接收js的回调函数,这样我们只需要添加swc这个包就可以使用js的所用功能。

其实我也不想使用eval的,eval是很消耗性能的,我的源代码长度大概是8万多,还好,没见卡,我也只会这种方法,不要拿板砖拍我哦!有其他办法的朋友告诉我哦!期望对某些人有帮助吧!

(0)

相关推荐

  • flex与js通信与彼此之间的互调整理(二)

    之前写了一篇flex和js之间的通信,还记得最开始研究这两门语言如何交互,一晃我的任务也快做完了,公司的realspace产品之开了js的API,但是现在使用flex产品的人也比较多,要求开设flex的三维API,已经过去几个月了,产品也上线了,有兴趣的可以在https://github.com/SuperMap/Flex-Realspace下载,这是一个利用as与js交互放在了一个完整的产品里. 网上也有很多关于flex和js通信的文章,不过不知道大家有没有注意到好像都需要把js文件放在固定的

  • flex与js通信与彼此之间的互调整理(一)

    由于这个迭代上面下发的任务中有一条:需要使用flex调用js来操控用ajax做的三维球,任务落在了我的身上,我也就才开始学习flex,以前用flash做过游戏,所以很快过了一遍语法就行了,开始网上查找flex和js之间互相调用的范例,这里整理一下也避免忘记,也和大家互相交流交流. 我用的是flash builder 4.6,也不熟悉. 一.flex调用js. 新建flex项目FlexToJs,如图所示: Felx调用js其实就是使用的方法ExternalInterface.call().主界面添

  • 嵌入式iframe子页面与父页面js通信的方法

    本文实例讲述了嵌入式iframe子页面与父页面js通信的方法.分享给大家供大家参考.具体分析如下: iframe框架中的页面与主页面之间的通信方式根据iframe中src属性是同域链接还是跨域链接,有明显不同的通信方式,同域下的数据交换和DOM元素互访就简单的多了,而跨域的则需要一些巧妙的方式来实现通信. 一.同域下父子页面的通信 父页面 parent.html: 复制代码 代码如下: <html> <head> <script type="text/javascr

  • JS中的数组方法笔记整理

    push()方法:可以向数组的末尾添加一个或者多个元素,并且返回新的长度 pop()方法:可以删除数组最后一个元素,并且返回被删除的元素,注意:如果数组是空的,该方法不进行任何操作,返回undefined. unshift()方法:可以向数组的开头添加一个或者多个元素,并且返回新的长度 shift()方法:可以删除数组第一个元素,并且返回被删除的元素,注意:如果数组是空的,该方法不进行任何操作,返回undefined. splice()方法:从数组中添加/删除项目,然后返回被删除的项目,该方法会

  • JS项目中对本地存储进行二次的封装的实现

    目录 前言 定义恒量的键名 下层实现 上层调用 总结 前言 平时在开发的中,发现身边同事在使用localStorage和sessionStorage的时候,喜欢在代码里面直接调用,举个的栗子: function login() { //...请求 const userInfo = {userId: 123, userName: '张三'} sessionStorage.setItem('userInfo', JSON.stringify(userInfo)) } function getUser

  • js调用Flex中的方法并向flex中传参及flex调用js示例

    首先,有了一个swf文件,test.swf,同时也有一个自动生成的html文件,test.html. 然后,在另外一个文件,test.jsp中,通过iframe,引入了test.html,即引入了swf. 现在想要在test.jsp中,向flex传参,并调用flex中的方法,我采用的方法是: 首先,在jsp中写一个调用flex的方法,如下 复制代码 代码如下: function initSWF(){ //得到swf的object var obj = window.frames["rightfra

  • flex通过js获取ip和pcname示例代码

    这个是在js中获取ip和pcname的方法,现在将它放在flex启动模板中即可.看代码: 复制代码 代码如下: function getClientPcName() { //"请将您浏览器Internet选项中的"对没有标记为安全的ActiveX控件进行初始化和脚本运行"设置为"启用"!\n\n然后刷新本页登陆!" var WshShellPcName = new ActiveXObject("WScript.Network"

  • Flex通过JS获取客户端IP和计算机名的实例代码

    首先说明一下,用JS方式获取不是调用webservices和httpservices. 在我们每一个FLex web工程中,都有那么一个文件夹bin-debug,里面有个index.html文件,我的个人理解是这样的,首先网页运行的时候,mxml的文件会被编译为swf,那么swf如何在浏览器中展现,就是通过这个html文件,相当于在html文件中嵌入了一个swf的object组件. www.jb51.net 所以,在这个html中写入js的代码,来获取ip地址我个人觉得是可行的.因此出现以下代码

  • iframe子页面与父页面在同域或不同域下的js通信

    iframe子页面与父页面通信根据iframe中src属性是同域链接还是跨域链接,通信方式也不同. 一.同域下父子页面的通信 父页面parent.html 复制代码 代码如下: <html> <head> <script type="text/javascript"> function say(){ alert("parent.html"); } function callChild(){ myFrame.window.say()

  • vue组件间通信子与父详解(二)

    接着vue组件父与子通信详解继续学习. 二.组件间通信(子组件传值给父组件) 通过事件的方式来完成数据的传输. ①在父组件中 定义一个方法,用来接收子组件所通过事件传来的值 methods:{ recvMsg:function(msg){ //参数msg就是子组件通过事件出来的数据 } } ②绑定事件处理函数 事件一般情况 都是自定义事件 <child-component @myEvent="recvMsg"></child-component> ③在子组件触发

随机推荐