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

相关文章

使用C++实现链表元素的反转

《使用C++实现链表元素的反转》反转链表是链表操作中一个经典的问题,也是面试中常见的考题,本文将从思路到实现一步步地讲解如何实现链表的反转,帮助初学者理解这一操作,我们将使用C++代码演示具体实现,同... 目录问题定义思路分析代码实现带头节点的链表代码讲解其他实现方式时间和空间复杂度分析总结问题定义给定

部署Vue项目到服务器后404错误的原因及解决方案

《部署Vue项目到服务器后404错误的原因及解决方案》文章介绍了Vue项目部署步骤以及404错误的解决方案,部署步骤包括构建项目、上传文件、配置Web服务器、重启Nginx和访问域名,404错误通常是... 目录一、vue项目部署步骤二、404错误原因及解决方案错误场景原因分析解决方案一、Vue项目部署步骤

前端原生js实现拖拽排课效果实例

《前端原生js实现拖拽排课效果实例》:本文主要介绍如何实现一个简单的课程表拖拽功能,通过HTML、CSS和JavaScript的配合,我们实现了课程项的拖拽、放置和显示功能,文中通过实例代码介绍的... 目录1. 效果展示2. 效果分析2.1 关键点2.2 实现方法3. 代码实现3.1 html部分3.2

CSS弹性布局常用设置方式

《CSS弹性布局常用设置方式》文章总结了CSS布局与样式的常用属性和技巧,包括视口单位、弹性盒子布局、浮动元素、背景和边框样式、文本和阴影效果、溢出隐藏、定位以及背景渐变等,通过这些技巧,可以实现复杂... 一、单位元素vm 1vm 为视口的1%vh 视口高的1%vmin 参照长边vmax 参照长边re

修改若依框架Token的过期时间问题

《修改若依框架Token的过期时间问题》本文介绍了如何修改若依框架中Token的过期时间,通过修改`application.yml`文件中的配置来实现,默认单位为分钟,希望此经验对大家有所帮助,也欢迎... 目录修改若依框架Token的过期时间修改Token的过期时间关闭Token的过期时js间总结修改若依

CSS3中使用flex和grid实现等高元素布局的示例代码

《CSS3中使用flex和grid实现等高元素布局的示例代码》:本文主要介绍了使用CSS3中的Flexbox和Grid布局实现等高元素布局的方法,通过简单的两列实现、每行放置3列以及全部代码的展示,展示了这两种布局方式的实现细节和效果,详细内容请阅读本文,希望能对你有所帮助... 过往的实现方法是使用浮动加

MySQL修改密码的四种实现方式

《MySQL修改密码的四种实现方式》文章主要介绍了如何使用命令行工具修改MySQL密码,包括使用`setpassword`命令和`mysqladmin`命令,此外,还详细描述了忘记密码时的处理方法,包... 目录mysql修改密码四种方式一、set password命令二、使用mysqladmin三、修改u

css渐变色背景|<gradient示例详解

《css渐变色背景|<gradient示例详解》CSS渐变是一种从一种颜色平滑过渡到另一种颜色的效果,可以作为元素的背景,它包括线性渐变、径向渐变和锥形渐变,本文介绍css渐变色背景|<gradien... 使用渐变色作为背景可以直接将渐China编程变色用作元素的背景,可以看做是一种特殊的背景图片。(是作为背

本地搭建DeepSeek-R1、WebUI的完整过程及访问

《本地搭建DeepSeek-R1、WebUI的完整过程及访问》:本文主要介绍本地搭建DeepSeek-R1、WebUI的完整过程及访问的相关资料,DeepSeek-R1是一个开源的人工智能平台,主... 目录背景       搭建准备基础概念搭建过程访问对话测试总结背景       最近几年,人工智能技术

Ollama整合open-webui的步骤及访问

《Ollama整合open-webui的步骤及访问》:本文主要介绍如何通过源码方式安装OpenWebUI,并详细说明了安装步骤、环境要求以及第一次使用时的账号注册和模型选择过程,需要的朋友可以参考... 目录安装环境要求步骤访问选择PjrIUE模型开始对话总结 安装官方安装地址:https://docs.