天天看點

CEF3研究之javascript內建(四

一、介紹

谷歌浏覽器和CEF使用V8JavaScript Engine作為内容的JavaScript實作。在浏覽器中的每個視窗都有它自己在的JS上下文提供作用域和在視窗中安全的執行JS代碼。CEF暴露大量JS功能內建在用戶端應用程式。

CEF3的Webkit和JS在單獨的渲染程序中運作。在渲染程序的主線程中使用TID_RENDERER 作為唯一辨別。所有V8的執行必須放置在這個線程中。

與JS執行相關的回調函數被暴露是通過CefRenderProcessHandler接口實作。當一個新的渲染程序被初始化時通過CefApp::GetRenderProcessHandler()函數擷取這個接口。

二、執行JavaScript

在用戶端應用程式中簡單的方式執行JS使用CefFrame::ExecuteJavaScript()函數,這個函數在浏覽程序一和渲染程序中都可用。在一個JS上下文外可安全使用。

CefRefPtr<CefBrowser> browser = ...;

CefRefPtr<CefFrame> frame = browser->GetMainFrame(); 

frame->ExecuteJavaScript("alert('ExecuteJavaScript works!');", frame->GetURL(), 0);

上面的引起alert('ExecuteJavaScript works!')在浏覽器的主視窗中執行。

在視窗的JS上下文中ExecuteJavaScript函數可用于函數和變量互動。是為了從JS到用戶端應用程式傳回值使用視窗綁定和擴充。

三、視窗綁定

 視窗綁定允許用戶端應用程式系上一個值到視窗的window對象上,視窗綁定的實作使用CefRenderProcessHandler::OnContextCreated()函數。

如:

void MyRenderProcessHandler::OnContextCreated(
    CefRefPtr<CefBrowser> browser,
    CefRefPtr<CefFrame> frame,
    CefRefPtr<CefV8Context> context) {
  // Retrieve the context's window object.
  CefRefPtr<CefV8Value> object = context->GetGlobal();

  // Create a new V8 string value. See the "Basic JS Types" section below.
  CefRefPtr<CefV8Value> str = CefV8Value::CreateString("My Value!");

  // Add the string to the window object as "window.myval". See the "JS Objects" section below.
  object->SetValue("myval", str, V8_PROPERTY_ATTRIBUTE_NONE);
}      

JavaScript架構可以與之互動的視窗綁定。

<script language="JavaScript">
alert(window.myval); // Shows an alert box with "My Value!"
</script>      

視窗綁定是每次重新加載一個架構加載給用戶端應用程式在必要時更改綁定的機會。例如,不同的架構通過修改綁定架構的視窗對象值可以通路不同的特性。

四、擴充

擴充像window綁定一樣除了為每個架構 加載到上下文之外,一旦加載就不能修改,當一個擴充已經加載并試圖在擴充加載中通路DOM就會出現DOM不存在的crash。擴充應該在CefRenderProcessHandler::OnWebKitInitialized()函數中使用CefRegisterExtension函數注冊。

void MyRenderProcessHandler::OnWebKitInitialized() {
  // Define the extension contents.
  std::string extensionCode =
    "var test;"
    "if (!test)"
    " test = {};"
    "(function() {"
    " test.myval = 'My Value!';"
    "})();";

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

通過extensionCode描述的字元串可以是任何有效的代碼,JS架構可以和擴充代碼進行互動

<script language="JavaScript">
alert(test.myval); // Shows an alert box with "My Value!"
</script>      

五、基本JS類型

CEF支援基本資料類型的建立,包括:undefined, null, bool, int, double, date 和 string.這些基本資料類型使用CefV8Value::Create*()系列靜态函數建立。如建立一個JS字元串:CefRefPtr<CefV8Value> str = CefV8Value::CreateString("My Value!");

基本資料類型可在任何地方建立和在所關聯的上下文中不用初始化。如:

CefRefPtr<CefV8Value> val = ...;

if (val.IsString())

{ // The value is a string. }

使用Get*Value()系列函數擷取值:CefString strVal = val.GetStringValue();

六、JS數組

使用CefV8Value::CreateArray()靜态函數并傳遞一個長度作為參數建立數組。數組隻能在上下文内部建立并使用。如:

CefRefPtr<CefV8Value> arr = CefV8Value::CreateArray(2);

 值賦給一個數組使用SetValue()方法的變體,以一個索引作為第一個參數。

arr->SetValue(0, CefV8Value::CreateString("My First String!"));

arr->SetValue(1, CefV8Value::CreateString("My Second String!"));

IsArray()函數測試CefV8Value是否為數組,GetArrayLength()函數擷取資料的長度,從數組中擷取一個值使用GetValue()變體函數。

七、JS對象

使用CefV8Value::CreateObject靜态函數可帶一個可選的CefV8Accessor參數建立JS對象。對象也隻能在js上下文中建立并使用。

 CefRefPtr<CefV8Value> obj = CefV8Value::CreateObject(NULL);

使用SetValue()變體函數并以字元串key作為第一參數給對象配置設定值。

八、對象的通路者

JS對象可選擇使用一個與之關聯的CefV8Accessor以提供一個源生的getting和setting值的實作。

CefRefPtr<CefV8Accessor> accessor = …;

CefRefPtr<CefV8Value> obj = CefV8Value::CreateObject(accessor);

CefV8Accessor接口的一個實作,必須由用戶端應用程式提供。

class MyV8Accessor : public CefV8Accessor {
public:
  MyV8Accessor() {}

  virtual bool Get(const CefString& name,
                   const CefRefPtr<CefV8Value> object,
                   CefRefPtr<CefV8Value>& retval,
                   CefString& exception) OVERRIDE {
    if (name == "myval") {
      // Return the value.
      retval = CefV8Value::CreateString(myval_);
      return true;
    }

    // Value does not exist.
    return false;
  }

  virtual bool Set(const CefString& name,
                   const CefRefPtr<CefV8Value> object,
                   const CefRefPtr<CefV8Value> value,
                   CefString& exception) OVERRIDE {
    if (name == "myval") {
      if (value.IsString()) {
        // Store the value.
        myval_ = value.GetStringValue();
      } else {
        // Throw an exception.
        exception = "Invalid value type";
      }
      return true;
    }

    // Value does not exist.
    return false;
  }

  // Variable used for storing the value.
  CefString myval_;

  // Provide the reference counting implementation for this class.
  IMPLEMENT_REFCOUNTING(MyV8Accessor);
};      

為了将值傳遞給通路者必須使用SetValue()變體函數設定,接受AccessControl和PropertyAttribute參數

九、JS函數

CEF支援JS函數建立和本地實作,