比如你选中了一段文字,需要在选中文字的前面或后面显示一个图标供用户操作,如下图
你选中的文本可以通过window.getSelection
去获取,但它可能是一个text
节点,你需要通过获取它的parent
节点,但如果你选中的只是这个parent
节点的一段文字,定位会不准确。
tips:关于如何实现上面的小冒泡,可以参考这篇地址的如何实现冒泡聊天框。
获取选中文字开头绝对定位
这时候可以通过window.getSelection().getRange(0)
其中的inserNode
函数往选中文字的前面插入一个空的行内标签,然后通过getBoundingClientRect
函数获取该节点相对于浏览器的位置,然后通过绝对定位减去你的气泡提示框的高度去实现定位到选中文字上方。
相关代码如下:
handleMouseup() {
const sel = window.getSelection()
const range = sel.getRangeAt(0)
// 选中文本
let text = range.toString()
// 提示气泡框
const tip = document.getElementById('tip')
if (!text) {
tip.style.display = 'none'
tip.style.top = '-99px'
tip.style.left = '-99px'
} else {
tip.style.display = 'block'
const span = document.createElement('span')
range.insertNode(span)
// 计算绝对定位
const pos = span.getBoundingClientRect()
tip.style.top = pos.top - 29/* 提示气泡框的高度 */ + 'px'
tip.style.left = pos.left + 'px'
span.remove()
}
}
获取选中文字结尾绝对定位
由于range
对象没有在选中文本结尾插入节点的函数,需要比和上面多两步操作:
①把选中节点折叠到结尾,在插入定位节点;
②重新选中文本。
另外,由于addRange
有兼容问题,需要换成setEnd
和setStart
函数来实现选中
相关代码如下:
handleMouseup() {
const sel = window.getSelection()
const range = sel.getRangeAt(0)
// 选中文本
let text = range.toString()
// 提示气泡框
const tip = document.getElementById('tip')
if (!text) {
tip.style.display = 'none'
tip.style.top = '-99px'
tip.style.left = '-99px'
} else {
tip.style.display = 'block'
// 定位到结尾
let copyRange = range.cloneRange()
sel.addRange(copyRange)
range.collapse()
const span = document.createElement('span')
range.insertNode(span)
// 计算绝对定位
const pos = span.getBoundingClientRect()
tip.style.top = pos.top - 29/* 提示气泡框的高度 */ + 'px'
tip.style.left = pos.left + 'px'
span.remove()
// 重新选中
range.setEnd(copyRange.endContainer, copyRange.endOffset)
range.setStart(copyRange.startContainer, copyRange.startOffset)
}
}