CEF中访问修改HTML DOM元素

2024-03-25 06:40

本文主要是介绍CEF中访问修改HTML DOM元素,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow

也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!

       

有时你可能想在C++代码中直接操作HTML中的某个元素,比如改变某个按钮的状态(文字、颜色)等,此时可以使用CEF提供的CefDomVisitor、CefDOMDocument、CefDomNode这三个类,包含cef_dom.h即可。

我们可以用它们完成下列任务:

  • 使用DOM模型访问HTML的各种节点(Element、Attribute、Text、CDATA、Comment、Document等)
  • 修改某个元素的属性
  • 修改某个Text节点的值

下面简要说说各个类的用法。

CefDOMDocument

CefDOMDocument对应JS里的document,不过功能少一些,类声明如下:

class CefDOMDocument : public virtual CefBase { public:  typedef cef_dom_document_type_t Type;  ///  // Returns the document type.  ///  /*--cef(default_retval=DOM_DOCUMENT_TYPE_UNKNOWN)--*/  virtual Type GetType() =0;  ///  // Returns the root document node.  ///  /*--cef()--*/  virtual CefRefPtr<CefDOMNode> GetDocument() =0;  ///  // Returns the BODY node of an HTML document.  ///  /*--cef()--*/  virtual CefRefPtr<CefDOMNode> GetBody() =0;  ///  // Returns the HEAD node of an HTML document.  ///  /*--cef()--*/  virtual CefRefPtr<CefDOMNode> GetHead() =0;  ///  // Returns the title of an HTML document.  ///  /*--cef()--*/  virtual CefString GetTitle() =0;  ///  // Returns the document element with the specified ID value.  ///  /*--cef()--*/  virtual CefRefPtr<CefDOMNode> GetElementById(const CefString& id) =0;  ///  // Returns the node that currently has keyboard focus.  ///  /*--cef()--*/  virtual CefRefPtr<CefDOMNode> GetFocusedNode() =0;  ///  // Returns true if a portion of the document is selected.  ///  /*--cef()--*/  virtual bool HasSelection() =0;  ///  // Returns the selection offset within the start node.  ///  /*--cef()--*/  virtual int GetSelectionStartOffset() =0;  ///  // Returns the selection offset within the end node.  ///  /*--cef()--*/  virtual int GetSelectionEndOffset() =0;  ///  // Returns the contents of this selection as markup.  ///  /*--cef()--*/  virtual CefString GetSelectionAsMarkup() =0;  ///  // Returns the contents of this selection as text.  ///  /*--cef()--*/  virtual CefString GetSelectionAsText() =0;  ///  // Returns the base URL for the document.  ///  /*--cef()--*/  virtual CefString GetBaseURL() =0;  ///  // Returns a complete URL based on the document base URL and the specified  // partial URL.  ///  /*--cef()--*/  virtual CefString GetCompleteURL(const CefString& partialURL) =0;};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89

如你所见,它能获取一些字符串值(URL、标题等),能根据id查找某个元素(在JS里我们最常用的方式),能返回Document、Head、Body等节点,这些节点的类型是CefDOMNode。

注意这个类的方法只能在Renderer进程的主线程上调用(TID_RENDERER)。

CefDOMNode

在 HTML DOM (文档对象模型)中,每个部分都是节点:

  • 文档本身是文档节点
  • 所有 HTML 元素是元素节点
  • 所有 HTML 属性是属性节点
  • HTML 元素内的文本是文本节点
  • 注释是注释节点

CefDOMNode代表了一个HTML DOM节点,它的声明如下:

class CefDOMNode : public virtual CefBase { public:  typedef std::map<CefString, CefString> AttributeMap;  typedef cef_dom_node_type_t Type;  ///  // Returns the type for this node.  ///  /*--cef(default_retval=DOM_NODE_TYPE_UNSUPPORTED)--*/  virtual Type GetType() =0;  ///  // Returns true if this is a text node.  ///  /*--cef()--*/  virtual bool IsText() =0;  ///  // Returns true if this is an element node.  ///  /*--cef()--*/  virtual bool IsElement() =0;  ///  // Returns true if this is an editable node.  ///  /*--cef()--*/  virtual bool IsEditable() =0;  ///  // Returns true if this is a form control element node.  ///  /*--cef()--*/  virtual bool IsFormControlElement() =0;  ///  // Returns the type of this form control element node.  ///  /*--cef()--*/  virtual CefString GetFormControlElementType() =0;  ///  // Returns true if this object is pointing to the same handle as |that|  // object.  ///  /*--cef()--*/  virtual bool IsSame(CefRefPtr<CefDOMNode> that) =0;  ///  // Returns the name of this node.  ///  /*--cef()--*/  virtual CefString GetName() =0;  ///  // Returns the value of this node.  ///  /*--cef()--*/  virtual CefString GetValue() =0;  ///  // Set the value of this node. Returns true on success.  ///  /*--cef()--*/  virtual bool SetValue(const CefString& value) =0;  ///  // Returns the contents of this node as markup.  ///  /*--cef()--*/  virtual CefString GetAsMarkup() =0;  ///  // Returns the document associated with this node.  ///  /*--cef()--*/  virtual CefRefPtr<CefDOMDocument> GetDocument() =0;  ///  // Returns the parent node.  ///  /*--cef()--*/  virtual CefRefPtr<CefDOMNode> GetParent() =0;  ///  // Returns the previous sibling node.  ///  /*--cef()--*/  virtual CefRefPtr<CefDOMNode> GetPreviousSibling() =0;  ///  // Returns the next sibling node.  ///  /*--cef()--*/  virtual CefRefPtr<CefDOMNode> GetNextSibling() =0;  ///  // Returns true if this node has child nodes.  ///  /*--cef()--*/  virtual bool HasChildren() =0;  ///  // Return the first child node.  ///  /*--cef()--*/  virtual CefRefPtr<CefDOMNode> GetFirstChild() =0;  ///  // Returns the last child node.  ///  /*--cef()--*/  virtual CefRefPtr<CefDOMNode> GetLastChild() =0;  // The following methods are valid only for element nodes.  ///  // Returns the tag name of this element.  ///  /*--cef()--*/  virtual CefString GetElementTagName() =0;  ///  // Returns true if this element has attributes.  ///  /*--cef()--*/  virtual bool HasElementAttributes() =0;  ///  // Returns true if this element has an attribute named |attrName|.  ///  /*--cef()--*/  virtual bool HasElementAttribute(const CefString& attrName) =0;  ///  // Returns the element attribute named |attrName|.  ///  /*--cef()--*/  virtual CefString GetElementAttribute(const CefString& attrName) =0;  ///  // Returns a map of all element attributes.  ///  /*--cef()--*/  virtual void GetElementAttributes(AttributeMap& attrMap) =0;  ///  // Set the value for the element attribute named |attrName|. Returns true on  // success.  ///  /*--cef()--*/  virtual bool SetElementAttribute(const CefString& attrName,                                   const CefString& value) =0;  ///  // Returns the inner text of the element.  ///  /*--cef()--*/  virtual CefString GetElementInnerText() =0;};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160

注意这个类的方法只能在Renderer进程的主线程上调用(TID_RENDERER)。

结合对HTML DOM节点的理解以及上面的代码,就能理解我们能使用CefDOMNode做什么:

  • 使用IsXXX或GetType判断节点类型
  • 使用GetNextSibling、GetPreviousSibling遍历兄弟节点
  • 如果是Text节点(叶子节点),SetValue可以改变其文本
  • 如果是Element节点,可以使用GetFirstChild、GetLastChild获取孩子,使用SetElementAttribute(s)改变属性,使用GetElementAttibute(s)获取属性

HTML DOM中的Element,有appendChild、insertBefore等方法,可以很方便地动态插入节点改变DOM和网页展示效果,而这个CefDOMNode就没有相应的方法,好像不太方便……

CefDOMVisitor

这个类的声明如下:

class CefDOMVisitor : public virtual CefBase { public:  ///  // Method executed for visiting the DOM. The document object passed to this  // method represents a snapshot of the DOM at the time this method is  // executed. DOM objects are only valid for the scope of this method. Do not  // keep references to or attempt to access any DOM objects outside the scope  // of this method.  ///  /*--cef()--*/  virtual void Visit(CefRefPtr<CefDOMDocument> document) =0;};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

要访问或修改HTML DOM,就必须实现这个类,然后将其对象传递给CefFrame::VisitDOM(CefRefPtr visitor)方法,最后你的Visit方法就被调用来访问或修改HTML DOM。

看一个简单的实现,显示DomVisitTestor类的声明:

class DomVisitTestor : public CefDOMVisitor{public:    DomVisitTestor();    void TestAccess(CefRefPtr<CefDOMDocument> document);    void TestModify(CefRefPtr<CefDOMDocument> document);    void Visit(CefRefPtr<CefDOMDocument> document) OVERRIDE;    IMPLEMENT_REFCOUNTING(DomVisitTestor);};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

然后是DomVisitTestor的实现:

void DomVisitTestor::TestAccess(CefRefPtr<CefDOMDocument> document){    OutputDebugStringW(L"DomVisitTestor::TestAccess\r\n");    OutputDebugStringW(document->GetTitle().ToWString().c_str());    OutputDebugStringW(document->GetBaseURL().ToWString().c_str());    CefRefPtr<CefDOMNode> headNode = document->GetHead();    OutputDebugStringW(headNode->GetName().ToWString().c_str());    OutputDebugStringW(headNode->GetAsMarkup().ToWString().c_str());    wchar_t szLog[512] = { 0 };    if (headNode->HasChildren())    {        CefRefPtr<CefDOMNode> childNode = headNode->GetFirstChild();        do         {            swprintf_s(szLog, 256, L"node name -%s, type-%d, value-%s\r\n",                childNode->GetName().ToWString().c_str(), childNode->GetType(), childNode->GetValue());            OutputDebugStringW(szLog);        } while ( (childNode = childNode->GetNextSibling()).get() );    }    CefRefPtr<CefDOMNode> bodyNode = document->GetBody();    OutputDebugStringW(bodyNode->GetAsMarkup().ToWString().c_str());    if (bodyNode->HasChildren())    {        CefRefPtr<CefDOMNode> childNode = bodyNode->GetFirstChild();        do        {            swprintf_s(szLog, 256, L"node name -%s, type-%d, value-%s\r\n",                childNode->GetName().ToWString().c_str(), childNode->GetType(), childNode->GetValue());            OutputDebugStringW(szLog);        } while ((childNode = childNode->GetNextSibling()).get());    }}void DomVisitTestor::TestModify(CefRefPtr<CefDOMDocument> document){    OutputDebugStringW(L"DomVisitTestor::TestModify\r\n");    CefRefPtr<CefDOMNode> bodyNode = document->GetBody();    if (bodyNode->HasChildren())    {        CefRefPtr<CefDOMNode> childNode = bodyNode->GetFirstChild();        wchar_t szLog[512] = { 0 };        do{            swprintf_s(szLog, 256, L"node name -%s,tagName-%s type-%d, value-%s\r\n",                childNode->GetName().ToWString().c_str(),                 childNode->GetElementTagName().ToWString().c_str(),                childNode->GetType(), childNode->GetValue());            OutputDebugStringW(szLog);            if (childNode->IsElement() && childNode->GetElementTagName() == "H1"                && childNode->GetElementAttribute("id") == "hello")            {                CefRefPtr<CefDOMNode> textNode = childNode->GetFirstChild();                swprintf_s(szLog, 512, L"found hello, text - %s\r\n", textNode->GetValue().ToWString().c_str());                OutputDebugStringW(szLog);                textNode->SetValue("Hello World Modified!");                break;            }        } while ((childNode = childNode->GetNextSibling()).get());    }    CefRefPtr<CefDOMNode> hello = document->GetElementById("hello");    if (hello.get())    {        hello->SetElementAttribute("align", "center");        OutputDebugStringW(L"Change hello align\r\n");    }}void DomVisitTestor::Visit(CefRefPtr<CefDOMDocument> document){    TestAccess(document);    TestModify(document);}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75

注意,这个类的方法也应当在Renderer进程的主线程(TID_RENDERER)上使用。

测试用的HTML文件如下:

<!DOCTYPE html><html>  <!--  Copyright (c) 2016 foruok(微信订阅号“程序视界”)  -->    <style type="text/css">    #divtest    {        position: relative;        left: 30px;        top: 10px;        padding: 10px;        width: 300px;        height: 200px;        background-color: gray;    }    </style><head>    <script type="text/javascript">      function test(){        window.DomVisitTest();      }    </script>    <title>Dom Visit Test</title></head><body><h1 id="hello">Hello</h1><form>  <input  type="button" value="VisitDom" onclick="test()"/></form>one<br>two<p>This is text</p><div id="divtest">  <p>div hello</p></div></body></html>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

你可能注意到我给VisitDom按钮关联的test()方法内调用了window.DomVisitTest()方法,该方法是我在C++代码中绑定到window对象上的,参考CEF中JavaScript与C++交互


就这样吧。

其他参考文章详见我的专栏:【CEF与PPAPI开发】。

           

给我老师的人工智能教程打call!http://blog.csdn.net/jiangjunshow
这里写图片描述

这篇关于CEF中访问修改HTML DOM元素的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/844145

相关文章

关于Java内存访问重排序的研究

《关于Java内存访问重排序的研究》文章主要介绍了重排序现象及其在多线程编程中的影响,包括内存可见性问题和Java内存模型中对重排序的规则... 目录什么是重排序重排序图解重排序实验as-if-serial语义内存访问重排序与内存可见性内存访问重排序与Java内存模型重排序示意表内存屏障内存屏障示意表Int

SpringBoot实现基于URL和IP的访问频率限制

《SpringBoot实现基于URL和IP的访问频率限制》在现代Web应用中,接口被恶意刷新或暴力请求是一种常见的攻击手段,为了保护系统资源,需要对接口的访问频率进行限制,下面我们就来看看如何使用... 目录1. 引言2. 项目依赖3. 配置 Redis4. 创建拦截器5. 注册拦截器6. 创建控制器8.

React实现原生APP切换效果

《React实现原生APP切换效果》最近需要使用Hybrid的方式开发一个APP,交互和原生APP相似并且需要IM通信,本文给大家介绍了使用React实现原生APP切换效果,文中通过代码示例讲解的非常... 目录背景需求概览技术栈实现步骤根据 react-router-dom 文档配置好路由添加过渡动画使用

JavaScript DOM操作与事件处理方法

《JavaScriptDOM操作与事件处理方法》本文通过一系列代码片段,详细介绍了如何使用JavaScript进行DOM操作、事件处理、属性操作、内容操作、尺寸和位置获取,以及实现简单的动画效果,涵... 目录前言1. 类名操作代码片段代码解析2. 属性操作代码片段代码解析3. 内容操作代码片段代码解析4.

SpringBoot如何访问jsp页面

《SpringBoot如何访问jsp页面》本文介绍了如何在SpringBoot项目中进行Web开发,包括创建项目、配置文件、添加依赖、控制层修改、测试效果以及在IDEA中进行配置的详细步骤... 目录SpringBoot如何访问JSP页python面简介实现步骤1. 首先创建的项目一定要是web项目2. 在

Linux限制ip访问的解决方案

《Linux限制ip访问的解决方案》为了修复安全扫描中发现的漏洞,我们需要对某些服务设置访问限制,具体来说,就是要确保只有指定的内部IP地址能够访问这些服务,所以本文给大家介绍了Linux限制ip访问... 目录背景:解决方案:使用Firewalld防火墙规则验证方法深度了解防火墙逻辑应用场景与扩展背景:

使用Vue.js报错:ReferenceError: “Vue is not defined“ 的原因与解决方案

《使用Vue.js报错:ReferenceError:“Vueisnotdefined“的原因与解决方案》在前端开发中,ReferenceError:Vueisnotdefined是一个常见... 目录一、错误描述二、错误成因分析三、解决方案1. 检查 vue.js 的引入方式2. 验证 npm 安装3.

vue如何监听对象或者数组某个属性的变化详解

《vue如何监听对象或者数组某个属性的变化详解》这篇文章主要给大家介绍了关于vue如何监听对象或者数组某个属性的变化,在Vue.js中可以通过watch监听属性变化并动态修改其他属性的值,watch通... 目录前言用watch监听深度监听使用计算属性watch和计算属性的区别在vue 3中使用watchE

Python使用pysmb库访问Windows共享文件夹的详细教程

《Python使用pysmb库访问Windows共享文件夹的详细教程》本教程旨在帮助您使用pysmb库,通过SMB(ServerMessageBlock)协议,轻松连接到Windows共享文件夹,并列... 目录前置条件步骤一:导入必要的模块步骤二:配置连接参数步骤三:实例化SMB连接对象并尝试连接步骤四:

python解析HTML并提取span标签中的文本

《python解析HTML并提取span标签中的文本》在网页开发和数据抓取过程中,我们经常需要从HTML页面中提取信息,尤其是span元素中的文本,span标签是一个行内元素,通常用于包装一小段文本或... 目录一、安装相关依赖二、html 页面结构三、使用 BeautifulSoup javascript