如何在Delphi Chromium Embedded中按名称获取元素?

前端之家收集整理的这篇文章主要介绍了如何在Delphi Chromium Embedded中按名称获取元素?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
要使用其ID从TChromium实例获取当前Web文档中嵌入的特定DOM节点,请使用ICefDomDocument.getElementById().但是如何通过NAME属性找到元素? Javascript具有document.getElementsByName()方法,而TWebBrowser(包装IE)也有类似的调用,但我无法弄清楚如何使用TChromium执行此操作.我需要找到一些具有NAME属性但没有ID属性的DOM元素.我搜查了ceflib单位并没有看到任何可以做到的事情.

边题.如果有人链接到TChromium“食谱”风格的网站或文档,我可以使用它.

更新:在等待答案时,我已经提出了以下代码来执行getElementsbyName().我想要比扫描整个DOM树更快.如果您在代码中看到错误,请告诉我:

type
    TDynamicCefDomNodeArray = array of ICefDomNode;


// Given a Chromium document interface reference and a NAME attribute to search for,//  return an array of all DOM nodes whose NAME attribute matches the desired.
function getElementsByName(ADocument: ICefDomDocument; theName: string): TDynamicCefDomNodeArray;

    // Get all the elements with a particular NAME attribute value and return
    //  an array of them.
    procedure getElementsByName1(intfParentNode: ICefDomNode; theName: string; var aryResults: TDynamicCefDomNodeArray);
    var
        oldLen: integer;
        intfChildNode: ICefDomNode;
        theNameAttr: string;
    begin
        Result := nil;
        intfChildNode := nil;

        if Assigned(intfParentNode) then
        begin
            // Attributes are case insensitive.
            theNameAttr := intfParentNode.GetElementAttribute('name');

            if AnsiSameText(theNameAttr,theName) then
            begin
                // Name attribute match.  Add it to the results array.
                oldLen := Length(aryResults);
                SetLength(aryResults,oldLen + 1);
                aryResults[oldLen] := intfParentNode;
            end; // if AnsiSameText(intfParentNode.Name,theName) then

            // Does the parent node have children?
            if intfParentNode.HasChildren then
            begin
                intfChildNode := intfParentNode.FirstChild;

                // Scan them.
                while Assigned(intfChildNode) do
                begin
                    getElementsByName1(intfChildNode,theName,aryResults);

                    if Assigned(intfChildNode) then
                        intfChildNode := intfChildNode.NextSibling;
                end;
            end; // if intfParentNode.HasChildren then
        end; // if Assigned(intfParentNode) then
    end;

    // ---------------------------------------------------------------

var
    intfCefDomNode: ICefDomNode;
begin
    intfCefDomNode := nil;
    Result := nil;

    if Assigned(ADocument) then
    begin
        // Check the header.
        intfCefDomNode := ADocument.Document;

        if Assigned(intfCefDomNode) then
        begin
            // Check the parent.
            getElementsByName1(intfCefDomNode,Result);
        end; // if Assigned(intfCefDomNode) then
    end; // if Assigned(ADocoument) then
end;

// ---------------------------------------------------------------

解决方法

目前还没有像 Chromium Embedded中内置的JavaScript getElementsByName或MSHTML getElementsByName以及它的Delphi包装器那样的功能.您只能通过迭代所有DOM元素来解决此问题,例如:通过创建自己的DOM访问者类,如下所示:

请注意,VisitDom过程是异步的,因此它会立即返回(实际上在DOM访问者完成访问之前)并且它在执行时与DOM的快照一起工作.

type
  TElementNameVisitor = class(TCefDomVisitorOwn)
  private
    FName: string;
  protected
    procedure visit(const document: ICefDomDocument); override;
  public
    constructor Create(const AName: string); reintroduce;
  end;

procedure ProcessElementsByName(const AFrame: ICefFrame; const AName: string);
var
  Visitor: TElementNameVisitor;
begin
  if Assigned(AFrame) then
  begin
    Visitor := TElementNameVisitor.Create(AName);
    AFrame.VisitDom(Visitor);
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  ProcessElementsByName(Chromium1.Browser.MainFrame,'NameAttributeValue');
end;

{ TDOMElementNameVisitor }

constructor TElementNameVisitor.Create(const AName: string);
begin
  inherited Create;
  FName := AName;
end;

procedure TElementNameVisitor.visit(const document: ICefDomDocument);

  procedure ProcessNode(ANode: ICefDomNode);
  var
    Node: ICefDomNode;
  begin
    if Assigned(ANode) then
    begin
      Node := ANode.FirstChild;
      while Assigned(Node) do
      begin
        if Node.GetElementAttribute('name') = FName then
        begin
          // do what you need with the Node here
          ShowMessage(Node.GetElementAttribute('value'));
        end;
        ProcessNode(Node);
        Node := Node.NextSibling;
      end;
    end;
  end;

begin
  ProcessNode(document.Body);
end;

猜你在找的Delphi相关文章