Ce3中的JS函数
CEF supports the creation of JS functions with native implementations.
Functions are created using the CefV8Value::CreateFunction() static
method that accepts name and CefV8Handler arguments. Functions can
only be created and used from within a context (see the “Working with
Contexts” section for more information).
CefRefPtr<CefV8Handler> handler = …;
CefRefPtr<CefV8Value> func = CefV8Value::CreateFunction("myfunc", handler);
class MyV8Handler : public CefV8Handler {
public:
MyV8Handler() {}
virtual bool Execute(const CefString& name,
CefRefPtr<CefV8Value> object,
const CefV8ValueList& arguments,
CefRefPtr<CefV8Value>& retval,
CefString& exception) OVERRIDE {
if (name == "myfunc") {
// Return my string value.
retval = CefV8Value::CreateString("My Value!");
return true;
}
// Function does not exist.
return false;
}
// Provide the reference counting implementation for this class.
IMPLEMENT_REFCOUNTING(MyV8Handler);
};
这个虚函数
virtual bool Execute( const CefString& name,
CefRefPtr< CefV8Value > object,
const CefV8ValueList& arguments,
CefRefPtr< CefV8Value >& retval,
CefString& exception )= 0
这里定义以name为标志的函数的执行。
object是接受者,也就是this,
arguments是传入的参数列表,
返回给调用者的值是用retval
exception是异常的字符串信息
Execute的返回值true表示函数已经得到处理,false表示没有被处理。
以下是官网的英文原文:https://magpcss.org/ceforum/apidocs3/
Handle execution of the function identified by |name|. |object| is the receiver (‘this’ object) of the function. |arguments| is the list of arguments passed to the function. If execution succeeds set |retval| to the function return value. If execution fails set |exception| to the exception that will be thrown. Return true if execution was handled.
我们还是通过实例来理解这段话。
index.html
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8" />
<script type="text/javascript" >
function showValue()
{
alert(window.say_yes);// c++提供的值(bind到浏览器window下)
}
function showAlert()
{
alert("this is test string from js");
}
function add()
{
// add 函数名不能与window对象挂接addFunction相同
try{
var result = window.addFunction(10, 20);// C++提供的接口,bind到window对象上
alert("10 + 20 = " + result);
}catch(err){
alert("error message is: " + err.message);
}
}
</script>
</head>
<body style="width:100%;height:100%;background-color:green;">
<p>这是c++与JS交互测试脚本</p>
<div >
<button onclick="showValue();">显示CEF中与窗口bind的test值</button>
<button onclick="add();">两个数相加</button>
</div>
</body>
</html>
Qt工程中添加文件
V8JsHandler.h
#pragma once
#include "include/cef_v8.h"
class CV8JsHandler : public CefV8Handler
{
public:
CV8JsHandler(void);
virtual ~CV8JsHandler() OVERRIDE;
public:
virtual bool Execute(const CefString& funcName,
CefRefPtr<CefV8Value> object,
const CefV8ValueList& arguments,
CefRefPtr<CefV8Value>& retval,
CefString& exception) OVERRIDE;
IMPLEMENT_REFCOUNTING(CV8JsHandler);
};
V8JsHandler.cpp
#include "V8JsHandler.h"
CV8JsHandler::CV8JsHandler(void)
{
}
CV8JsHandler::~CV8JsHandler(void)
{
}
bool CV8JsHandler::Execute(const CefString& funcName,
CefRefPtr<CefV8Value> object,
const CefV8ValueList& arguments,
CefRefPtr<CefV8Value>& retval,
CefString& exception)
{
if (funcName == "addFunction")
{
int32 nSum = 0;
for (size_t i = 0; i < arguments.size(); ++i)
{
if(!arguments[i]->IsInt())
return false;
nSum += arguments[i]->GetIntValue();
}
retval = CefV8Value::CreateInt(nSum);
return true;
}
return false;
}
simple_app.h文件中:
#pragma once
#include "include/cef_app.h"
class SimpleApp
: public CefApp
, public CefBrowserProcessHandler
, public CefRenderProcessHandler
{
public:
SimpleApp(void);
virtual ~SimpleApp() OVERRIDE;
public:
virtual CefRefPtr<CefBrowserProcessHandler> GetBrowserProcessHandler() OVERRIDE;
virtual CefRefPtr<CefRenderProcessHandler> GetRenderProcessHandler() OVERRIDE;
virtual void OnContextCreated(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefV8Context> context) OVERRIDE;
protected:
IMPLEMENT_REFCOUNTING(SimpleApp);
};
在simple_app.cc中
#include "V8JsHandler.h"
//..中间省略
void SimpleApp::OnContextCreated(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context)
{
// The var type can accept all object or variable
CefRefPtr<CefV8Value> window = context->GetGlobal();
// bind value into window[or you can bind value into window sub node]
CefRefPtr<CefV8Value> strValue = CefV8Value::CreateString("say yes");
window->SetValue("say_yes", strValue, V8_PROPERTY_ATTRIBUTE_NONE);
// bind function
CefRefPtr<CV8JsHandler> pJsHandler(new CV8JsHandler());
CefRefPtr<CefV8Value> myFunc = CefV8Value::CreateFunction("addFunction", pJsHandler);
window->SetValue("addFunction", myFunc, V8_PROPERTY_ATTRIBUTE_NONE);
}
现在已经将我们的JS函数addFunction,绑定在window对象上了。
运行结果:
接下来我们开始测试刚才官方的那段话中返回值和异常信息。
index.html内容改成:
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8" />
<script type="text/javascript" >
function showValue()
{
alert(window.say_yes);// c++提供的值(bind到浏览器window下)
}
function showAlert()
{
alert("this is test string from js");
}
function add()
{
// add 函数名不能与window对象挂接addFunction相同
try{
var result = window.addFunction(10, 20);// C++提供的接口,bind到window对象上
alert("10 + 20 = " + result);
}catch(err){
alert("error message is: " + err.message);
}
}
function add2()
{
//alert(g_value);
try{
var result = window.addFunction2(10, 20);// C++提供的接口,bind到window对象上
alert("10 + 20 = " + result);
}catch(err){
alert("error message is: " + err.message);
}
}
function add3()
{
//alert(g_value);
try{
var result = window.addFunction3(10, 20);// C++提供的接口,bind到window对象上
alert("10 + 20 = " + result);
}catch(err){
alert("error message is: " + err.message);
}
}
function add4()
{
//alert(g_value);
try{
var result = window.addFunction4(10, 20);// C++提供的接口,bind到window对象上
alert("10 + 20 = " + result);
}catch(err){
alert("error message is: " + err.message);
}
}
function add5()
{
//alert(g_value);
try{
var result = window.addFunction5(10, 20);// C++提供的接口,bind到window对象上
alert("10 + 20 = " + result);
}catch(err){
alert("error message is: " + err.message);
}
}
</script>
</head>
<body style="width:100%;height:100%;background-color:green;">
<p>这是c++与JS交互测试脚本</p>
<div >
<button onclick="showValue();">显示CEF中与窗口bind的test值</button>
<button onclick="add();">两个数相加</button>
<button onclick="add2();">两个数相加,异常</button>
<button onclick="add3();">两个数相加,返回值和异常</button>
<button onclick="add4();">测试已注册</button>
<button onclick="add5();">测试未注册</button
</div>
</body>
</html>
V8JsHandler.cpp
#include "V8JsHandler.h"
CV8JsHandler::CV8JsHandler(void)
{
}
CV8JsHandler::~CV8JsHandler(void)
{
}
bool CV8JsHandler::Execute(const CefString& funcName,
CefRefPtr<CefV8Value> object,
const CefV8ValueList& arguments,
CefRefPtr<CefV8Value>& retval,
CefString& exception)
{
if (funcName == "addFunction")
{
int32 nSum = 0;
for (size_t i = 0; i < arguments.size(); ++i)
{
if(!arguments[i]->IsInt())
return false;
nSum += arguments[i]->GetIntValue();
}
retval = CefV8Value::CreateInt(nSum);
return true;
}
else if (funcName == "addFunction2")
{
exception = "not found!";
return true;
}
else if (funcName == "addFunction3")
{
int32 nSum = 0;
for (size_t i = 0; i < arguments.size(); ++i)
{
if(!arguments[i]->IsInt())
return false;
nSum += arguments[i]->GetIntValue();
}
retval = CefV8Value::CreateInt(nSum);
exception = "not found!";
return true;
}
return false;
}
simple_app.cc中的OnContextCreated函数
void SimpleApp::OnContextCreated(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context)
{
// The var type can accept all object or variable
CefRefPtr<CefV8Value> window = context->GetGlobal();
// bind value into window[or you can bind value into window sub node]
CefRefPtr<CefV8Value> strValue = CefV8Value::CreateString("say yes");
window->SetValue("say_yes", strValue, V8_PROPERTY_ATTRIBUTE_NONE);
// bind function
CefRefPtr<CV8JsHandler> pJsHandler(new CV8JsHandler());
CefRefPtr<CefV8Value> myFunc = CefV8Value::CreateFunction("addFunction", pJsHandler);
window->SetValue("addFunction", myFunc, V8_PROPERTY_ATTRIBUTE_NONE);
CefRefPtr<CefV8Value> myFunc2 = CefV8Value::CreateFunction("addFunction2", pJsHandler);
window->SetValue("addFunction2", myFunc2, V8_PROPERTY_ATTRIBUTE_NONE);
CefRefPtr<CefV8Value> myFunc3 = CefV8Value::CreateFunction("addFunction3", pJsHandler);
window->SetValue("addFunction3", myFunc3, V8_PROPERTY_ATTRIBUTE_NONE);
CefRefPtr<CefV8Value> myFunc4 = CefV8Value::CreateFunction("addFunction4", pJsHandler);
window->SetValue("addFunction4", myFunc4, V8_PROPERTY_ATTRIBUTE_NONE);
}
运行:
(1)
(2)
(3)
(4)
(5)
结论:
- 首先先要绑定到window对象中,否则会在JS中报出异常is not a function
- 对于已经绑定到window对象的JS函数,CV8JsHandler::Execute函数中返回true,表示该JS被处理;返回false表示未被处理
- 对于已经被处理的JS函数(Execute中返回true表示该JS函数已经被处理),retval的是给JS的返回值,exception是异常字符串,如果两者同时存在,则exception会被先抛出异常
- Execute中返回false表示该JS函数未被处理,JS中会得到一个undefined
需要注意的点:
(1)表示是CV8JsHandler,这里可以是将不同的JS函数对象放到不同的CV8JsHandler子类中,然后把这个智能指针放到1处
(2)表示的是CV8JsHandler中的JS函数名
(3)表示的是在网页中的JS调用的名称,比如window.addFunction 这样调用
在index.html中
function add()
{
// add 函数名不能与window对象挂接addFunction相同
try{
var result = window.addFunction(10, 20);// C++提供的接口,bind到window对象上
alert("10 + 20 = " + result);
}catch(err){
alert("error message is: " + err.message);
}
}
add 函数名不能与window对象挂接addFunction相同,这个也需要注意。
链接:https://pan.baidu.com/s/1Hs7R1HjrKvZhNS6nri8zig
提取码:9mes