文章都是发布在github再转到这边的,这边格式可能会乱掉.博客地址:benqy.com

写在前面的废话

公司首页的flash广告,都是由第三方制作的,脚本和flash文件都是由各个广告公司独立制作,然后在我们页面引用.这样的方式肯定不靠谱,页面脚本非常的乱,因此现在想收回脚本控制权,采用的方式是要求广告公司做出的flash素材要按要求实现接口供js调用,并且实现类似事件的机制,在广告的各个状态切换时通知页面脚本.

以前都没接触过flash,现在只好临阵磨枪,挑一些会用到的学习一下,顺便记下来.

这篇主要讲讲js和as3之间如何交互,如何实现简单的类似事件的机制.

模拟事件

在as3中,无论是调用js的方法,还是暴露接口给js,都是用ExternalInterface这个api.
暴露接口:ExternalInterface.addCallback(函数名, 函数)
调用js方法:ExternalInterface.call(方法名, 参数)

这里所说的模拟事件,就是在falsh素材的各个状态切换时,通知页面.如加载完毕时,触发onload事件,播放时触发onplay,停止时触发onstop等等.

采用的方案,是在object标签里,添加自定义的属性供as3调用,属性名是flash定死的:flashvars,值的格式类似url里的参数部分,为用&分隔的键值对,如下:

在as3中,这样读取属性:

flashvars= LoaderInfo( this.root.loaderInfo ).parameters;

flashvars是一个object变量,定义如下:

private var flashvars:Object;

读取后,flashvars的值:

Object {onload: "advnr70wyu5xncanvpwzzo0pory66", onplay: "advf4q8r99cfnryhn2tk2n3s48kf0", onstop: "adv7sgjk0529cd00q6ojuf537"}

对象的key为事件名,值为事件处理函数名,所有事件处理函数都在window.flashCallback命名空间下,并且名字是随机生成的不可重复的guid.

在as3里,我们判断是否支持调用js函数:

ExternalInterface.available

以onload事件为例,在素材加载完毕后,如果支持调用js函数,则触发onload事件:

//素材加载完毕,调用onload
private function onload():void {
if (ExternalInterface.available) {
textField.text = 'onload';
if(flashvars.onload){
ExternalInterface.call("window.flashCallback." + flashvars.onload);
}
}
}

上面提到,函数名是随机生成的,类似jquery的$.ajax方法里的callback实现方式,以下是封装过的生成object标签的方法:

//adv.flash.embed是封装过的生成object标签的方法
asyncTest('flash标签自定义事件', function () {
expect(3);
document.body.appendChild(adv.flash.embed({
id: 'flashGetSWF',
source: 'test.swf',
params: {
onload: function () {
this.play();
ok(true);
},
onplay: function () {
ok(true);
this.stop();
},
onstop: function () {
ok(true);
start();
}
}
}));
});

几个回调函数都是匿名函数,在生成标签之前,会给函数在window.flashCallback下分配一个随机名称.现在只是简单的实现单个事件处理函数的绑定,如果有需要支持多个,只要再做一些简单的封装即可.

adv.flash.embed的实现要点:

//遍历自定义参数
adv.util.forEach(params, function (value, key) {
var funcVar = value;
if (adv.util.isFunction(value)) {
//如果是函数,则生成一个随机的名称,并存储在flashCallback命名空间下
funcVar = adv.util.guid();
window.flashCallback[funcVar] = function() {
var swfObj = adv.flash.getSWF(id);
//this指向flash对象本身
value.apply(swfObj, arguments);
};
}
paramArr.push(key + '=' + funcVar);
});

执行结果:

暴露接口给js

as3里,实现这个很简单,先上代码再说:

public function test() {
flashvars= LoaderInfo( this.root.loaderInfo ).parameters;
//此为调试用
ExternalInterface.call("window.flashCallback.trace",flashvars);
//加载素材
textField.width=200;
textField.height = 90;
addChild(textField);
//素材加载完毕,准备播放
//暴露api给js
if(ExternalInterface.available){
ExternalInterface.addCallback("play", play);
ExternalInterface.addCallback("stop", stop);
}
//触发onload
onload();
} //这个方法被调用时,开始播放
private function play():Boolean {
textField.text = 'play';
if(flashvars.onplay){
ExternalInterface.call("window.flashCallback." + flashvars.onplay);
}
return true;
} //这个方法被调用时,停止播放
private function stop():Boolean {
textField.text = 'stop';
if(flashvars.onstop){
ExternalInterface.call("window.flashCallback." + flashvars.onstop,flashvars);
}
return true;
}

这里定义了两个方法,play和stop,在构造函数(test)里,判断ExternalInterface是否可用,如果可用,就暴露出这两个方法:

ExternalInterface.addCallback("play", play);
ExternalInterface.addCallback("stop", stop);

在js里调用:

跨浏览器的获取flash对象引用方法

...
getSWF:function(name) {
if (navigator.appName.indexOf("Microsoft") != -1) {
return window[name];
} else {
return document[name];
}
}
...

暴露出的as3方法,会直接附加在object对象上,要注意的是,我们要等onload之后才去调用,保证falsh加载完毕:

asyncTest('js调用flash方法', function () {
expect(1);
document.body.appendChild(adv.flash.embed({
id: 'flashcallSWF',
source: 'test.swf',
width: 300,
height: 190,
params: {
onload: function () {
var result = this.play();
ok(result);
start();
}
}
}));
});

事件函数的this指向flash对象,所以这里不用再获取了

执行结果:

完整的as3代码:

package {
import flash.display.LoaderInfo;
import flash.display.Sprite;
import flash.external.ExternalInterface;
import flash.text.TextField; public class test extends Sprite {
private var flashvars:Object;
//用textField文本的改变来代表广告播放的状态转变
private var textField:TextField = new TextField();
public function test() {
flashvars= LoaderInfo( this.root.loaderInfo ).parameters;
//加载素材
textField.width=200;
textField.height = 90;
addChild(textField);
//素材加载完毕,准备播放
//暴露api给js
if(ExternalInterface.available){
ExternalInterface.addCallback("play", play);
ExternalInterface.addCallback("stop", stop);
}
//触发onload
onload();
} //这个方法被调用时,开始播放
private function play():Boolean {
textField.text = 'play';
if(flashvars.onplay){
ExternalInterface.call("window.flashCallback." + flashvars.onplay);
}
return true;
} //这个方法被调用时,停止播放
private function stop():Boolean {
textField.text = 'stop';
if(flashvars.onstop){
ExternalInterface.call("window.flashCallback." + flashvars.onstop,flashvars);
}
return true;
} private function onload():void {
if (ExternalInterface.available) {
textField.text = 'onload';
if(flashvars.onload){
ExternalInterface.call("window.flashCallback." + flashvars.onload);
}
}
}
}
}

javascript与as3交互的更多相关文章

  1. iOS中JavaScript和OC交互

    转载自:http://www.devzeng.com/blog/ios-uiwebview-interaction-with-javascript.html 还可参考的文章:http://blog.c ...

  2. jQuery基础与JavaScript与CSS交互-第五章

    目录 JavaScript框架种类及其优缺点 jQuery库 jQuery对象$ 掌握基本选择器 掌握过滤选择器 掌握表单选择器 RIA技术 常见的RIA技术 Ajax Sliverlight Fle ...

  3. 在android中实现webview与javascript之间的交互(转)

    参见“在android中实现webview与javascript之间的交互”

  4. Hybrid App: 对比UIWebView和WebKit实现JavaScript与Native交互

    一.简介 在前面一篇文章中讲到过实现JavaScript与Native交互的方式有一种就是使用原生内嵌webView.在iOS8之前,开发者只能使用苹果提供的UIWebView类来加载URL或者HTM ...

  5. Qt和JavaScript使用QWebChannel交互一——和Qt内嵌网页交互

    Qt和JavaScript使用QWebChannel交互一--和Qt内嵌网页交互 目录 Qt和JavaScript使用QWebChannel交互一--和Qt内嵌网页交互 前言 一.效果 二.实现过程 ...

  6. iOS中JavaScript和OC交互 --by 胡 xu

    在iOS开发中很多时候我们会和UIWebView打交道,目前国内的很多应用都采用了UIWebView的混合编程技术,最常见的是微信公众号的内容页面.前段时间在做微信公众平台相关的开发,发现很多应用场景 ...

  7. Duilib嵌入CEF以及JavaScript与C++交互

    转载:http://blog.csdn.net/foruok/article/details/50573612 转载:http://blog.csdn.net/foruok/article/detai ...

  8. iOS UIWebView中javascript与Objective-C交互、获取摄像头

    UIWebView是iOS开发中常用的一个视图控件,多数情况下,它被用来显示HTML格式的内容. 支持的文档格式 除了HTML以外,UIWebView还支持iWork, Office等文档格式: Ex ...

  9. 【iOS开发】UIWebView与JavaScript(JS) 回调交互

    ------------------------------------------------- 很多关于objc 与 js 交互的文章都比较适用于 mac开发,iOS的webview 还是有所不一 ...

随机推荐

  1. Redis设置记录

    首先大前提是,这个redis使用的外网端口,需要在防火墙或者安全组中打开 正常在redis配置文件里有个bind,这个默认是127.0.0.1,如果不修改,就是内网可以访问. 这里有个点需要提一下,就 ...

  2. .ner core InvalidOperationException: Cannot find compilation library location for package 'xxx' 和 SqlException: 'OFFSET' 附近有语法错误。 在 FETCH 语句中选项 NEXT 的用法无效。问题

    原文地址:传送门 1.InvalidOperationException: Cannot find compilation library location for package 'xxx'问题: ...

  3. 跨集群拷贝hdfs

    拷贝 A集群的test目录到B集群的test目录 问题1: cause:java.io.IOException: Failed to run job : User root cannot submit ...

  4. MySql笔记之修改MySQL提示符

    首先,了解下MYSQL提示符是神马东东 就是每次登陆mysql后出现的提示符 如果我们不喜欢这个提示符呢,那我们就改成我们喜欢的样子. 系统参数提示符 举个栗子 就改成相应的提示符了,那么可否随意改名 ...

  5. 深入JS正则先行断言

    这里是 Mastering Lookahead and Lookbehind 文章的简单翻译,这篇文章是在自己搜索问题的时候stackoverflow上回答问题的人推荐的,看完觉得写得很不错.这里的简 ...

  6. POJ2955 Brackets(区间DP)

    给一个括号序列,求有几个括号是匹配的. dp[i][j]表示序列[i,j]的匹配数 dp[i][j]=dp[i+1][j-1]+2(括号i和括号j匹配) dp[i][j]=max(dp[i][k]+d ...

  7. Bean装配--xml

    1,bean package com.songyan.zhangpei; import java.util.ArrayList; import com.sun.xml.internal.bind.v2 ...

  8. Lazy Scheduler:我的轻量级任务调度框架

    一.背景 工作中经常涉及任务调度,一直都是采用while(true) => if hitted DO => Thread.Sleep(interval)的模式.但是最近实在是感觉这种实现模 ...

  9. 通过PHP current()函数获取未知字符键名数组第一个元素的值

    在开发中经常遇到这样问题,获取数组第一个元素的值,如果是数字索引那还好,直接$array[0],如果键名是字符串,你又未知这个字符串呢?用current()函数就可以做到. 当然,你可以用array_ ...

  10. Makefile学习之通配符和自动变量

    规则中的通配符 “*” ,“?” ,“ [...]”, " % " , " wildcard " 1.“*”  *.c表示所有后缀为.C的文件: 如果文件中用到 ...