鼠标选中文本弹出悬浮框,计算选中文字的位置。
@mouseup.stop="handleMouseUp"
<div class="cont" id="textareaCont">
<textarea @select.stop="onSelect" @keydown="onKeyDown" ref="origintext" v-model="origin"></textarea>
</div>
<div class="crossword" ref="crossword" v-if="crossword" :style="crosswordStyle"></div>
mounted() {
document.addEventListener("mousedown", this.handleOutsideClick)
}
beforeUnmount(){
document.removeEventListener("mousedown", this.handleOutsideClick)
}
选中事件
handleMouseUp(event) {
// 设置划词区域
if (!this.$refs.resultmain.contains(event.target)) {
return
}
const selection = window.getSelection()
const selectedText = selection.toString().trim()
if (!selectedText) {
return
}
const {
startContainer, // 起始节点
startOffset, // 起始节点偏移量
endContainer, // 终止节点
endOffset, // 终止节点偏移量
} = document.getSelection().getRangeAt(0)
// 创建一个 range 对象
const range = document.createRange()
// 设置需要获取位置信息的文本节点以及偏移量
range.setStart(startContainer, startOffset)
range.setEnd(startContainer, startContainer.textContent.length)
// 通过 getBoundingClientRect 获取位置信息
const rect = range.getBoundingClientRect()
if (selectedText) {
// 设置弹框样式 并且设置偏移量
this.crosswordStyle = {
top: rect.top + 40 - 130 + "px",
left: rect.left + 40 + "px",
}
}
},
输入框选中事件
onSelect(){
// 获取 textarea DOM 元素
const textarea = this.$refs.origintext
const selection = window.getSelection()
// 获取选中文本的起始位置和结束位置
const selectionStart = textarea.selectionStart
const selectionEnd = textarea.selectionEnd
const selectedText = selection.toString().trim()
if (!selectedText) {
return
}
// 获取选中文本的绝对定位
const absolutePosition = this.getAbsolutePosition(
textarea,
selectionStart,
selectionEnd
)
this.crosswordStyle = {
top: absolutePosition.top + 40 - 130 + "px",
left: absolutePosition.left + 40 + "px",
}
}
getAbsolutePosition(textarea, start, end){
// 创建一个临时的 div 元素,用于计算选中文本的位置
const div = document.createElement("div")
// document.body.appendChild(div)
// 设置 div 的样式,使其与 textarea 相似
const style = getComputedStyle(textarea)
div.style.cssText = style.cssText
div.style.position = "absolute"
// div.style.visibility = 'hidden'
div.style.whiteSpace = "pre-wrap"
div.style.wordWrap = "break-word"
div.style.width = textarea.clientWidth + "px"
div.style.top = 0
div.style.background = "transparent"
div.style.zIndex = 2
div.style.color = "transparent"
// 将 textarea 的文本内容添加到 div 中,并插入一个 span 元素表示选中文本
const text =
textarea.value.substring(0, start) +
"<span >" +
textarea.value.substring(start, end) +
"</span>" +
textarea.value.substring(end)
div.innerHTML = text.replace(/\n/g, "<br>")
let parent = document.querySelector("#textareaCont")
parent.insertBefore(div, parent.firstChild)
// 计算选中文本的位置
const span = div.querySelector("span")
const rect = span.getBoundingClientRect()
// 移除 div 元素
document.querySelector("#textareaCont").removeChild(div)
// 返回选中文本的绝对定位
return {
top: rect.top,
left: rect.left,
width: rect.width,
height: rect.height,
}
}
关闭弹框
handleOutsideClick(event){
// 如果点击弹框不关闭弹框
if (event.target.className == "crossword") {
return
}
if (this.$refs.crossword && this.$refs.crossword.contains(event.target)) {
return
}
this.crossword = false
const selection = window.getSelection()
// 手动取消选中
selection.removeAllRanges()
}