【方法】
JSAPI 对javascript暴露了四种基本类型的接口(Methods, Properties, Attributes, and Events),每一种接口都必须在JSAPI对象的构造函数中注册(Attributes和Events除外)。
Attributes可以在任何一个除了析构函数的函数中注册(registerAttribute(const std::string& str, const FB:variant& value, bool readOnly = false));
Events在1.5.0之后的版本中注册是在类声明中FB_JSAPI_EVENT(不带on的函数名全小写, 参数个数, (参数类型列表)); 在cpp文件里的函数中fire_funcName(参数s)即可。
Methods:方法如果没有明确返回一个值则返回undefined,就像js函数。
如果想从js传一个【字典】类型的参数,那么形参可以用std::map(或者任何其他的STL字典类型,比如hash_map, multimap等),但键应该是std::string类型,值可以是任何JSAPIAuto支持的类型。
这是唯一值传递的情况,如果你需要用引用传递一个对象,那么形参应该接受为一个FB::JSObjectPtr类型,并且使用Invoke, GetProperty, SetProperty来操作它。
如果想从js传一个【数组】类型的参数,那么形参可以用std::vector(或者任何其他STL列表类型,比如list, set等),容器中的元素类型可以是任何JSAPI支持的类型。
JSAPIAuto类型支持 继承自FB::variant所支持的类型。 当JSAPIAuto把一个参数转换成你的JSAPI方法或属性期望的类型时,它是通过使用FB::variant::convert_cast
FireBreath支持的类型:
数学类型:signed/unsigned int/long/short/char, float, double, size_t
布尔类型:true false
string: FireBreath支持std::string和std::wstring,并且会自动的在两者之间进行转换,需要注意的是:std::string表达式一直都是UTF-8编码
char* 和 wchar_t*:只有作为返回类型(或者assign to a FB::variant)你能使用char* wchar_t*,但是这些会在内部被转换为std::string和std::wstring。
二进制数据:如果你需要传递二进制数据给页面,我们建议你要么转换成一个string(hex, base64等),要么包装成javascipt Array(比如std::vector
容器类型:FB支持所有的STL容器,并且是100%的兼容。 联合类型可以作为参数传递给JSAPI函数并且js对象会自动的转换,反之,非联合类型可以从js对象中保持数据。
方法的注册: registerMethod("mytestEvent", make_method(this, &cuihaoidentiferAPI::testEvent));
注意:需要在js中访问的方法才需要注册,否则可以不用注册。 上例中mytestEvent为暴露给js的函数名,make_method后为真正的函数名。
【属性】
属性分为只读属性和读写属性,属性也是靠函数实现的,即set和get,如下
registerProperty("mystr", make_property(this, &cuihaoidentiferAPI::get_myString, &cuihaoidentiferAPI::set_myString));
上例中是一个读写属性,因为有get和set,如果是只读属性则只写get即可,方法如下:
std::string get_myString();
void set_myString(const std::string& str);
这样的方法不需要注册,因为不需要被js访问。
【Attribute】
这个东西应该翻译成什么呢? Attribute和【属性累死】,也分为只读和读写,但是区别是Attribute没有复杂的代码逻辑,只需要注册一下即可,
void FB::JSAPIAuto::registerAttribute( const std::string &name, const FB::variant& value, bool readonly /*= false*/ ),
而这个注册不需要在构造函数里,在任何函数中注册都可以,默认为读写属性,第三个参数为true时即为只读,虽然叫做只读的,但是仅仅是不可以在javascript中改变其值,在C++中还是可以改变其值的。
void cuihaoidentiferAPI::regAttriWR() //对js提供的注册Attribute的函数
{
registerAttribute("first", 100);
}
void cuihaoidentiferAPI::regAttriROnly() //对js提供的注册Attribute的函数
{
registerAttribute("second", "cuihao", true);
}
可是,但是,可但是,请注意根据我自己的实验发现:
1、当没有调用注册Attribute的函数registerAttribute时,得到的属性值为undefined(符合预期);
2、当在js中用代码在没有调用registerAttribute的情况下给Attribute赋值时却可以赋值成功,并且就算是只读的也可以赋值成功,
这一点不太明白。
【Event】事件
由于浏览器的差异,强烈建议命名事件时遵循如下原则:
1、所有字母小写
2、事件名字必须以"on"开头
例如:
onload onstart ondead onsomethingelse ....
FB 1.5.0中的新特性
事件必须总是使用相同的参数个数和参数类型被触发,最后我们在你的JSAPI类上增加了创建方法的宏,这样就能在js中触发事件。这是由你的JSAPI类中的FB_JSAPI_EVENT宏来完成的。 写在class声明中!
语法个数如下:
FB_JSAPI_EVENT({事件名(不带on)}, {参数个数}, {参数类型列表})
eg.
/
class ClassName
{
public:
FB_JSAPI_EVENT(load, 0, ()) //名字为load,参数个数为0,没有参数类型
FB_JSAPI_EVENT(update, 1, (int)) // 名字为update, 一个参数, 类型为int
FB_JSAPI_EVENT(rename, 2, (const std::string& old, const std::string& new)) //名字为rename,参数为2个, /// //类型为const std::string
}
///
触发事件:
void ClassName::fireAllEvents()
{
fire_load();
fire_update(10);
fire("old name", "new name");
}
///
注意:永远不要在析构函数中触发事件(fire event),这样会导致未定义的行为,也许会使得页面重新加载的时候插件崩溃!
在js中使用events:为了在js中处理你的插件中的事件,你需要在插件对象中listen for it。
在所有的IE版本尤其是IE9中, 必须使用attachEvent函数来添加事件,尽管addEventListener在IE9中也是可用的,但是IE从来不会把事件句柄传递给插件,所以如果你不使用attachEvent这样可能会导致失败!
注意:调用attchEvent函数添加事件的时候必须加上“on”! 另外有用户反映在IE中的embed标签中使用插件可能会导致事件不能正常工作,所以请你在OBJECT标签中使用。
function onPluginLoad() //对应load事件,无参数
{
alert("I am loadding!");
}
function onPluginUpdate(num) //对应update事件,参数为一个int类型
{
alert("number is " + num);
}
function onPluginRename(old, new)
{
alert(old + " " + new);
}
function testEvent()
{
var plugin = document.getElementById("pluginID");
plugin.attachEvent("on" + "load", onPluginLoad);
plugin.attachEvent("on" + "update", );
plugin.attachEvent("on" + "rename", onPluginRename);
}
///
在其他浏览器中使用(except IE):使用addEventListener函数来添加事件,而用这个函数添加事件则不需要在事件名前手动加"on",会自动添加"on"。
function onPluginLoad()
{
alert("I ma loadding!");
}
function onPluginUpdate(num)
{
alert("number is " + num);
}
function testEvent()
{
var plugin = document.getElementById("pluginID");
plugin.addEventListener("load", onPluginLoad, false); //addEventListener有三个参数
plugin.addEventListener("update", onPluginUpdate, false); //addEventListener有三个参数
}
///自适应不同浏览器///
function testEvent()
{
var plugin = document.getElementById("pluginID");
if(plugin.attachEvent) //IE, 或者是判断浏览器内核
{
plugin.attachEvent("on" + "load", onPluginLoad);
}
else
{
plugin.addEventListener("load", onPluginLoad, false);
}
}
注意:FB不支持"useCapture"参数,即addEventListener的第三个参数,忽略,写false为保持语法正确,true也可。
卸载事件:IE;detachEvent(), 非IE:removeEventListener()。
/
在FB 1.5.0 之前的版本中:
注册事件(在构造函数中):
class ClassName
{
public:
registerEvent("onload");
registerEvent("onupdate");
}
///...................
触发事件:
void ClassName::FireEvents()
{
//this->FireEvent("event name", params); //event name包括"on",
//params是一个FB::VariantList(std::vector
this->FireEvent("onload", FB::variant_list_of());
this->FireEvent("onupdate", FB::variant_list_of(10));
}
//
再谈实参 形参
js传一个数组参数给插件的方法:在插件的方法中可以使用FB:VariantList做形参或者是任何一个适应实参的STL容器类型。
eg.
plugin.func(new Array(1, "2", 3.0));
//FB::VariantList做形参
bool func(FB::VariantList& array);
//STL做形参
bool func(std::vector
如果实参是一个js对象,那么形参可以是一个FB::JSObjectPtr& obj类型。
如果实参是一个js函数,js函数同样也是对象,也可以使用FB::JSObjectPtr& func类型。
如果实参是一组可变参数,那么形参可以使用FB::CatchAll& args,比如:
//js
plugin.add('my stuff', 1, "2", 3.0)'
//.cpp
bool MyAPI::add(const FB::CatchAll& args)
{
const FB::VariantList& values = args.value;
std::string a = values[0].convert_cast
int b = values[1].convert_case
//....
return true;
}
//
返回基本类型
所有被FB::variant支持的简单类型都可以直接返回。
返回容器
可以直接返回FB::VariantList 和 FB::VariantMap类型
return FB::variant_list_of(1)(2)(3);
return FB::variant_map_of(1, 2)(3, 4)(5, 6);
返回对象
返回的对象毕竟已经实现了FB::JSAPI,并且FB:JSAPIPtr应该作为返回类型。
return boost::make_shared
其中SomeObject必须已经实现了JSAPI。