【方法】
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<type>來完成的。
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<unsigned char>)。 傳遞行業內的數據作爲js數組不會特別有效率,但是插件接口不允許二進制數據。 所有的strings都假設瀏覽器爲UTF-8編碼,所以簡單的返回一個char*可能會產生不可預期的結果。
容器類型: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<FB::variant>)。
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<std::string>& array);
如果實參是一個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<std::string>();
int b = values[1].convert_case<int>();
//....
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>(m_browserHost),
其中SomeObject必須已經實現了JSAPI。