本文主要是介绍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元素的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!