如何获取 HTML 元素以及用户在元素文本中单击的位置

How to get the HTML element and the position in the element's text where a person has clicked

使用 Internet Explorer 我想获得一个人点击文本的位置。 3 到 4 个字符的错误是可以的。文本不可编辑,通常在 span 元素中。

我知道我可以为 HTMLDocument 设置一个点击事件侦听器,但是我并不总是拥有 HTMLDocument 对象,因此可能会错过该事件。

我已经尝试获取 IHTMLSelectionObject,然后使用 IHTMLTxtRange 创建文本范围,但是当仅单击网页而不是选择至少 1 个字符时,IHTMLTxtRange 具有 HTMLBody 的父级而不是单击的元素。

HTMLDocument.activeElement也不靠谱。在我的测试中,它实际上从未 returns 元素单击过,它通常 returns 树上某处元素的主要父元素。

使用 MSHTML 是否有其他方法可以实现此目的?

我也试过使用 WIN API GetCursorPos 但是我不知道如何处理这个位置,我不知道如何将它转换成实际元素。

编辑: 我还想到了一个有趣的想法。当我需要知道有光标的元素时,我在整个文档上设置了一个 mouseDown 或 click 事件。然后触发我自己的点击并捕捉事件。在事件的 IHTMLEventObj 中有一个 FromElement,我希望它能告诉我光标在哪里。似乎对于 mouseDown 和 click 事件总是没有任何意义。至少对我来说,这个对象仅用于例如鼠标悬停事件。

以下是我至少选择了一个字符时的结果。

 Private Function GetHTMLSelection(ByVal aDoc As IHTMLDocument2, ByRef htmlText As String) As Integer

    Dim sel As IHTMLSelectionObject = Nothing
    Dim selectionRange As IHTMLTxtRange = Nothing
    Dim rangeParent As IHTMLElement4 = Nothing
    Dim duplicateRange As IHTMLTxtRange = Nothing
    Dim i As Integer
    Dim x As Integer
    Dim found As Boolean

    Try
        'get a selection
        sel = TryCast(aDoc.selection, IHTMLSelectionObject)

        If sel Is Nothing Then
            Return -1
        End If
        'the range of the selection.
        selectionRange = TryCast(sel.createRange, IHTMLTxtRange)

        If selectionRange Is Nothing Then
            Return -1
        End If
        'the the parent element of the range.
        rangeParent = TryCast(selectionRange.parentElement, IHTMLElement4)

        'duplicate our range so we can manipulate it.
        duplicateRange = TryCast(selectionRange.duplicate, IHTMLTxtRange)

        'make the dulicate range the whole element text.
        duplicateRange.moveToElementText(rangeParent)

        'get the length of the whole text
        i = duplicateRange.text.Length

        For x = 1 To i
            duplicateRange.moveStart("character", 1)

            If duplicateRange.compareEndPoints("StartToStart", selectionRange) = 0 Then
                found = True
                Exit For
            End If

        Next

        If found Then
            Debug.Print("Position is: " + x.ToString)
            htmlText = duplicateRange.text
            Return x
        Else
            Return -1
        End If


    Catch ex As Exception
        Return -1
    Finally

    End Try


End Function

我无法post用一个很好的函数来回答如何做到这一点,但我会解释重要的部分。

  1. 使用 Win32 API GetCursorPos 获取屏幕上用户最后单击的位置。
  2. 如果您有 iFrame,这意味着不止一个 HTMLDocument,那么您需要遍历 iFrame 并使用 HTMLFrameElement clientWidth 和 clientHeight 以及 IHTMLWindow3 screenTop 和 screenLeft 来找出您的观点在哪个 HTMLDocument 上。
  3. 使用您在数字 2 中找到的 IHTMLWindow 将此点转换为相对点。
  4. 获得正确的 HTMLDocument 和与此文档相关的点后,您就可以在 IHTMLDocument2 对象上使用 elementFromPoint 方法。
  5. 一旦你有了这个,你现在就知道点击的点和元素了。

    私有函数 getElementTextPosition() 作为布尔值

        Dim sel As IHTMLSelectionObject = Nothing
        Dim selectionRange As IHTMLTxtRange = Nothing
        Dim duplicateRange As IHTMLTxtRange = Nothing
        Dim i As Integer = 0
        Dim found As Boolean
        Dim x As Integer
    
        Try
            'elementWithCursor is a IHTMLElement class variable
            If elementWithCursor IsNot Nothing Then
                ReleaseComObject(elementWithCursor)
                elementWithCursor = Nothing
            End If
            'docWithCursor is also a IHTMLDocument2 class variable
            'cursorPointInDoc is the point relative to the actual document 
            elementWithCursor = TryCast(docWithCursor.elementFromPoint(cursorPointInDoc.X, cursorPointInDoc.Y), IHTMLElement)
    
            If elementWithCursor Is Nothing Then
                Return False
            End If
    
            'get a selection
            sel = TryCast(docWithCursor.selection, IHTMLSelectionObject)
    
            If sel Is Nothing Then
                Return False
            End If
    
            selectionRange = TryCast(sel.createRange, IHTMLTxtRange)
    
            If selectionRange Is Nothing Then
                Return False
            End If
    
            'First check if We have selection text so we will use that as the selected text
            '_SelectedText relates to a class property
            If selectionRange.text IsNot Nothing Then
                _SelectedText = selectionRange.text
                selectionRange.collapse(True)
            Else
                'the the parent element of the range.
                selectionRange.moveToPoint(cursorPointInDoc.X, cursorPointInDoc.Y)
            End If
    
            'duplicate our range so we can manipulate it.
            duplicateRange = TryCast(selectionRange.duplicate, IHTMLTxtRange)
    
            'make the dulicate range the whole element text.
            duplicateRange.moveToElementText(elementWithCursor)
    
            'get the length of the whole text
            i = duplicateRange.text.Length
    
            For x = 0 To i
    
                If duplicateRange.compareEndPoints("StartToStart", selectionRange) = 0 Then
                    found = True
                    Exit For
                End If
    
                duplicateRange.moveStart("character", 1)
    
            Next
    
            If found Then
                '_CursorPositionInText is a class property and relates to the position where the person clicked in the html text.
                _CursorPositionInText = x
                _HTMLElementText = elementWithCursor.innerText
    
                Return True
            Else
                Return False
            End If
    
        Catch ex As Exception
            Return False
        End Try
    
    End Function