Cef3中js与C++交互(二)——window绑定JS函数

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

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值