CEF 中的 JavaScript

CEF 利用 V8 JS 引擎来实现 JS。

  • 浏览器中的每一个 frame 都有自己的 JS 上下文,JS 只能在该上下文中执行。
  • JS 只能在渲染进程中的 TID_RENDERER 线程中执行。
  • 有关 JS 回调的接口都包含在 CefRenderProcessHandler 中,因此我们要实现这个接口来对 JS 进行扩展。这个接口一般由 CefApp 实现。

执行 JavaScript

可以通过 CefFrame::ExecuteJavaScript() 来执行 JS。该函数可以脱离 JS 上下文,在浏览器进程和渲染进程中都可以执行。例如可以在浏览器创建成功后调用该函数执行一段 JS 脚本:

class MyClient : public CefClient, public CefLifeSpanHandler
{

    ...

    virtual void OnAfterCreated(CefRefPtr<CefBrowser> browser) override
    {
        ...

        auto frame = browser->GetMainFrame();
        frame->ExecuteJavaScript("alert('Hello, JS!');", frame->GetURL(), 0);
    }

    ...
};
  • 1绑定值到Window对象

可以在 CefRenderProcessHandler::OnContextCreated() 中绑定一些值给 JS 的 window 对象。下面举几个例子。

绑定值

class MyApp : ... , public CefRenderProcessHandler
{
    ...
    virtual void OnContextCreated(CefRefPtr<CefBrowser> browser,
        CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context) override
    {
        CEF_REQUIRE_RENDERER_THREAD();

        // 获取 window 对象
        CefRefPtr<CefV8Value> object = context->GetGlobal();

        // 床架一个 JS 字符串
        CefRefPtr<CefV8Value> str = CefV8Value::CreateString("Hello, JS!");

        // 将创建的字符串绑定到 window 的 greet 属性
        object->SetValue("greet", str, V8_PROPERTY_ATTRIBUTE_NONE);
    }
};
  •  
<script language="JavaScript">
    alert(window.greet);
</script>

绑定函数

如果要绑定函数,则需要实现 CefV8Handler 来作为函数的处理器:

class MyV8Handler : public CefV8Handler 
{
    ...

    virtual bool Execute(const CefString& name, CefRefPtr<CefV8Value> object,
        const CefV8ValueList& arguments, CefRefPtr<CefV8Value>& retval, 
        CefString& exception) override
    {
        CEF_REQUIRE_RENDERER_THREAD();

        if (name == "add")  // 处理函数 add
        {
            auto num1 = arguments[0]->GetIntValue();  // 参数1
            auto num2 = arguments[1]->GetIntValue();  // 参数2
            auto sum = num1 + num2;
            retval = CefV8Value::CreateInt(sum);
            return true;
        }

        // Function does not exist.
        return false;
    }

    ...
};

class MyApp : ..., public CefRenderProcessHandler
{
    ...

    virtual void OnContextCreated(CefRefPtr<CefBrowser> browser,
        CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context) override
    {
        CEF_REQUIRE_RENDERER_THREAD();

        CefRefPtr<CefV8Value> object = context->GetGlobal();

        // 创建函数处理器
        CefRefPtr<CefV8Handler> handler = new MyV8Handler();

        // 创建函数
        CefRefPtr<CefV8Value> func = CefV8Value::CreateFunction("add", handler);

        // 将函数绑定为 window 的 add 属性
        object->SetValue("add", func, V8_PROPERTY_ATTRIBUTE_NONE);
    }
};
  • 1

在 JS 中:

<script language="JavaScript">
    alert(window.add(1,2));
</script>
  • 1
  • 2
  • 3

扩展JS

可以在 CefRenderProcessHandler::OnWebKitInitialized() 中将 JS 脚本注入到 V8 中。

扩展值

class MyApp : ..., public CefRenderProcessHandler
{
    ...

    virtual void OnWebKitInitialized() override
    {
        CEF_REQUIRE_RENDERER_THREAD();

        // Define the extension contents.
        std::string extensionCode =
            "var test;"
            "if (!test)"
            "  test = {};"
            "(function() {"
            "  test.myval = 'Hello JS!';"
            "})();";

        // Register the extension.
        CefRegisterExtension("v8/test", extensionCode, NULL);
    }
};

在 JS 中:

<script language="JavaScript">
    alert(test.myval);
</script>
  • 扩展函数

如果要扩展函数,则需要实现 CefV8Handler 来作为函数的处理器:

class MyV8Handler : public CefV8Handler 
{
    ...

    virtual bool Execute(const CefString& name, CefRefPtr<CefV8Value> object,
        const CefV8ValueList& arguments, CefRefPtr<CefV8Value>& retval, 
        CefString& exception) override
    {
        CEF_REQUIRE_RENDERER_THREAD();

        if (name == "add")
        {
            auto num1 = arguments[0]->GetIntValue();
            auto num2 = arguments[1]->GetIntValue();

            auto sum = num1 + num2;

            std::ostringstream oss;
            oss << num1 << " + " << num2 << " = " << sum << std::endl;
            OutputDebugStringA(oss.str().c_str());

            retval = CefV8Value::CreateInt(sum);

            return true;
        }

        // Function does not exist.
        return false;
    }

    ...
};

class MyApp : ..., public CefRenderProcessHandler
{
    ...

    virtual void OnWebKitInitialized() override
    {
        CEF_REQUIRE_RENDERER_THREAD();

        // Define the extension contents.
        std::string extensionCode =
            "var test;"
            "if (!test)"
            "  test = {};"
            "(function() {"
            "  test.add = function(num1, num2) {"
            "    native function add(num1, num2);"
            "    return add(num1, num2);"
            "  };"
            "})();";

        // Create an instance of my CefV8Handler object.
        CefRefPtr<CefV8Handler> handler = new MyV8Handler();

        // Register the extension.
        CefRegisterExtension("v8/test", extensionCode, handler);
    }

    ...
};

在 JS 中:

<script language="JavaScript">
    alert(test.add(1,2));
</script>
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值