如何获取 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用一个很好的函数来回答如何做到这一点,但我会解释重要的部分。
- 使用 Win32 API GetCursorPos 获取屏幕上用户最后单击的位置。
- 如果您有 iFrame,这意味着不止一个 HTMLDocument,那么您需要遍历 iFrame 并使用 HTMLFrameElement clientWidth 和 clientHeight 以及 IHTMLWindow3 screenTop 和 screenLeft 来找出您的观点在哪个 HTMLDocument 上。
- 使用您在数字 2 中找到的 IHTMLWindow 将此点转换为相对点。
- 获得正确的 HTMLDocument 和与此文档相关的点后,您就可以在 IHTMLDocument2 对象上使用 elementFromPoint 方法。
一旦你有了这个,你现在就知道点击的点和元素了。
私有函数 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
使用 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用一个很好的函数来回答如何做到这一点,但我会解释重要的部分。
- 使用 Win32 API GetCursorPos 获取屏幕上用户最后单击的位置。
- 如果您有 iFrame,这意味着不止一个 HTMLDocument,那么您需要遍历 iFrame 并使用 HTMLFrameElement clientWidth 和 clientHeight 以及 IHTMLWindow3 screenTop 和 screenLeft 来找出您的观点在哪个 HTMLDocument 上。
- 使用您在数字 2 中找到的 IHTMLWindow 将此点转换为相对点。
- 获得正确的 HTMLDocument 和与此文档相关的点后,您就可以在 IHTMLDocument2 对象上使用 elementFromPoint 方法。
一旦你有了这个,你现在就知道点击的点和元素了。
私有函数 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