CHtmlView 加载完成消息获取

我使用 MFC CHtmlView 类视图打开了目标网页,里面有个div如下图,该div内容是通过ajax动态获取的,html源文件是没有内容的。

Navigate2后,OnDocumentComplete 和 OnNavigateComplete2 消息回调时 div 内容还没有显示出来了。若人工检测,完全加载完页面后,再执行函数,采用 IDispatch IHTMLDocument3 IHTMLElementCollection IHTMLElement 等结合,是可以获取到 div 的 innerHTML

请教如何判断目标网页的完全加载,或者准确的说,是判断目标 div 已经ajax动态加载完毕?
或者谁能给段有效的代码,使用 IHTMLElement getAttribute 获取div class属性值

img

该回答引用ChatGPT

遇到问题可以回复我

您可以通过以下几种方式来判断目标 div 是否已经ajax动态加载完毕:

1、使用JavaScript:您可以在页面加载时通过JavaScript监听目标 div 的加载事件,当该 div 加载完成后触发回调函数,以此来判断目标 div 是否已经加载完成。例如,您可以使用以下代码来监听目标 div 的加载事件:

var targetDiv = document.querySelector('.blockcontent');
targetDiv.addEventListener('load', function() {
  // 目标 div 加载完成后的处理逻辑
});


2、监听XMLHttpRequest的onreadystatechange事件:如果目标 div 是通过ajax动态获取的,那么可以通过监听XMLHttpRequest对象的onreadystatechange事件来判断目标 div 是否已经加载完成。当XMLHttpRequest对象的readyState属性为4时,表示请求已完成,可以通过XMLHttpRequest对象的responseText属性获取返回的HTML代码,从而判断目标 div 是否已经加载完成。例如,您可以使用以下代码来监听XMLHttpRequest对象的onreadystatechange事件:


var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
  if (xhr.readyState === 4) {
    var html = xhr.responseText;
    // 在返回的HTML代码中查找目标 div,判断其是否已经加载完成
  }
};
xhr.open('GET', 'http://example.com/ajax_request', true);
xhr.send();

3、使用jQuery的load方法:如果您的应用中使用了jQuery库,您可以使用jQuery的load方法来加载目标 div,并通过load方法的回调函数来判断目标 div 是否已经加载完成。例如,您可以使用以下代码来加载目标 div 并判断其是否已经加载完成:


$('.blockcontent').load('http://example.com/ajax_request', function() {
  // 目标 div 加载完成后的处理逻辑
});

该回答内容部分引用GPT,GPT_Pro更好的解决问题
CHtmlView 加载完成消息获取

要判断目标网页是否完全加载,我们可以使用MFC 的CHtmlView 类视图来实现。CHtmlView 类视图提供了多个消息回调函数,如OnDocumentComplete 和 OnNavigateComplete2,当页面加载完成时,这两个函数就会被调用。

在这两个函数中,我们可以通过IDispatch、IHTMLDocument3、IHTMLEIlementCollection 和 IHTMLElement 等结合,来获取div的innerHTML。IHTMLElementCollection 是一种DOM 元素的集合,可以通过item 函数来获取某一个元素;通过innerHTML 属性可以获取元素的内容。

//声明 HTML 文档对象
CComPtr<IHTMLDocument2> m_spHtmlDoc; 
//声明元素集合对象
CComPtr<IHTMLElementCollection> m_spEleCol; 
//声明元素对象
CComPtr<IHTMLElement> m_spEle; 
//声明内部 HTML 字符串
CComBSTR sHtml; 
//声明内部文本字符串
CComBSTR sText; 
// 定义元素 ID 字符串 
CComBSTR sId = "block_content"; 
// 获取 HTML 文档对象 
m_spHtmlDoc = m_pBrowser->GetHtmlDocument(); 
// 获取元素集合对象 
m_spHtmlDoc->get_all(&m_spEleCol); 
// 通过 ID 获取某一个元素 
m_spEleCol->item(CComVariant(sId), CComVariant(0), &m_spEle); 
// 获取元素的 innerHTML 
m_spEle->get_innerHTML(&sHtml); 
// 获取元素的 innerText 
m_spEle->get_innerText(&sText);  

通过上面的代码,我们就能够判断目标div是否已经ajax动态加载完毕,从而达到判断目标页面是否完全加载的目的。
如果回答有帮助,望采纳。

该回答引用GPTᴼᴾᴱᴺᴬᴵ
您可以通过在 MFC CHtmlView 类中覆盖 OnDownloadComplete 或者 OnQuit 方法来获取网页加载完成的消息。在 OnDownloadComplete 方法中,您可以检查是否存在目标 div,以判断它是否已经动态加载完毕。下面是一个简单的示例代码:

class CMyHtmlView : public CHtmlView
{
public:
    virtual void OnDownloadComplete();
};

void CMyHtmlView::OnDownloadComplete()
{
    CHtmlView::OnDownloadComplete();

    // 获取 HTML 文档对象
    CComPtr<IHTMLDocument2> spDoc = GetHtmlDocument();

    // 获取目标 div
    CComPtr<IHTMLElement> spElement;
    spDoc->getElementById(L"myDiv", &spElement);

    if (spElement)
    {
        // 目标 div 存在,表示已经加载完毕
        // 在这里获取 div 的 innerHTML
        CString strHtml;
        spElement->get_innerHTML(strHtml.GetBufferSetLength(1024), 1024);
        strHtml.ReleaseBuffer();
    }
}

在上面的代码中,我们首先调用了 CHtmlView::OnDownloadComplete 方法来确保页面已经完全加载完毕。然后,我们获取了 HTML 文档对象,并使用它来查找目标 div。如果目标 div 存在,我们就可以在这里获取它的 innerHTML。

需要注意的是,上面的代码中假定目标 div 的 id 是 "myDiv"。如果您的目标 div 的 id 不同,需要相应地修改代码。另外,由于这个方法是在加载完成后立即执行的,因此如果目标 div 是通过 JavaScript 动态加载的,可能还需要等待一段时间才能获取到它。在这种情况下,您可能需要使用定时器或者其他技术来等待目标 div 加载完成。

可以通过在 CHtmlView 类中重写 OnDownloadComplete() 函数来判断页面是否已经完全加载。当页面上所有资源都被下载完成时,OnDownloadComplete() 函数会被调用。但是这个函数只能检测到页面所有资源是否加载完成,而无法判断特定的 div 是否已经加载完毕,以下是示例代码:

// 在 CHtmlView 类中添加以下代码

LRESULT CHtmlView::OnDivLoaded(WPARAM wParam, LPARAM lParam)
{
    // 在这里处理 div 加载完成后的逻辑
    return 0;
}

void CHtmlView::OnDocumentComplete(LPCTSTR lpszURL)
{
    // 在文档加载完成后注册 div 加载事件监听器
    CString strJavaScript;
    strJavaScript.Format(_T("document.getElementById('div_id').addEventListener('load', function() { \
        window.external.NotifyDivLoaded(); \
    });"));
    GetHtmlDocument()->parentWindow->execScript(strJavaScript, _T("JavaScript"));

    CHtmlView::OnDocumentComplete(lpszURL);
}

BEGIN_DHTML_EVENT_MAP(CHtmlView)
    DHTML_EVENT_ONCLICK(_T("a"), OnClickAnchor)
    DHTML_EVENT_ONCLICK(DISPID_HTMLELEMENTEVENTS_ONCLICK, OnClick)
    DHTML_EVENT_ONSUBMIT(_T("form"), OnSubmitForm)
    DHTML_EVENT_ONCHANGE(_T("input"), OnChangeInput)
    DHTML_EVENT_ONKEYPRESS(_T("body"), OnKeyPress)
END_DHTML_EVENT_MAP()

// 在 DHTML 事件映射中添加以下代码

DHTML_EVENT_ONCALL(_T("NotifyDivLoaded"), OnDivLoaded)

若对你有所帮助,望采纳。

参考GPT和自己的思路,您可以通过检查目标 div 是否存在来判断它是否已经动态加载完毕。在 MFC CHtmlView 中,您可以在 OnDocumentComplete 或 OnNavigateComplete2 中使用 IHTMLDocument3 接口访问文档的元素,并使用 IHTMLElementCollection 接口查找具有特定 ID 的元素。

以下是一个示例代码片段,它使用 IHTMLElementCollection 接口在文档中查找 ID 为“target_div”的元素:

void CMyHtmlView::OnDocumentComplete(LPCTSTR lpszURL) {
    CHTMLView::OnDocumentComplete(lpszURL);

    // Get the document's IHTMLDocument3 interface
    CComPtr<IHTMLDocument3> spDocument;
    if (SUCCEEDED(GetHtmlDocument()->QueryInterface(IID_IHTMLDocument3, (void**)&spDocument))) {
        // Find the target div element by ID
        CComBSTR bstrId(L"target_div");
        CComPtr<IHTMLElementCollection> spElements;
        spDocument->getElementsByName(bstrId, &spElements);

        long nCount = 0;
        if (SUCCEEDED(spElements->get_length(&nCount)) && nCount > 0) {
            // The target div element exists
            // Do something with its inner HTML
            CComPtr<IHTMLElement> spElement;
            spElements->item(0, 0, &spElement);

            CComBSTR bstrHtml;
            spElement->get_innerHTML(&bstrHtml);
            CString strHtml = bstrHtml;
            // ...
        }
        else {
            // The target div element does not exist yet
            // Wait for it to be loaded
            // ...
        }
    }
}

如果在 OnDocumentComplete 中找不到目标 div 元素,则可以等待一段时间后再次检查,直到元素出现为止。您可以使用定时器、线程等机制实现此等待。但是请注意,等待时间过长可能会导致界面不流畅或卡死,应根据具体情况适当调整等待时间。

以下答案基于ChatGPT与GISer Liu编写:

在 MFC 的 CHtmlView 类中,可以通过重载 OnDownloadComplete 函数来捕捉 AJAX 动态加载完成的事件。当 AJAX 请求完成后,该函数会被调用,可以在该函数中获取 div 的内容。

以下是一个示例代码,其中在 OnDownloadComplete 函数中获取了 div 的 class 属性值:

class CMyHtmlView : public CHtmlView
{
public:
    CMyHtmlView() {}

    DECLARE_DYNCREATE(CMyHtmlView)

    virtual void OnDownloadComplete() override
    {
        // 基类函数需要调用,确保完成后视图正常显示
        CHtmlView::OnDownloadComplete();

        // 获取 div 元素
        IHTMLDocument2* pDoc = GetHtmlDocument();
        if (pDoc)
        {
            CComPtr<IHTMLElement> pDiv;
            pDoc->getElementById(L"block_content", &pDiv);
            if (pDiv)
            {
                // 获取 class 属性值
                CComBSTR bstrClass;
                pDiv->getAttribute(L"class", 0, &bstrClass);
                CString strClass = bstrClass;
                AfxMessageBox(strClass);
            }
        }
    }

    // 省略其他代码...
};

在 OnDownloadComplete 函数中,首先调用了基类函数确保视图能够正常显示,然后获取了 div 元素,并通过 IHTMLElement 的 getAttribute 函数获取了其 class 属性值。可以根据实际需求修改获取元素的方式,比如根据 class 名称或标签名称等方式获取元素。

需要注意的是,OnDownloadComplete 只能在页面完全加载完成后才会被调用,如果 div 的内容是通过多个 AJAX 请求加载的,可能需要等待多个 OnDownloadComplete 函数被调用才能确保内容全部加载完成。

分两种情况考虑:
1、如果是你可以修改的div,可以在div加载完毕后主动发送消息给CHtmlViewer;
2、如果不能修改div和js。需要动态获取div状态判断是否加载完成再进行你想的操作,可能需要你定时轮询来实现。
有帮助请采纳,谢谢!