We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
mdn的定义:
Selection 对象表示用户选择的文本范围或插入符号的当前位置。它代表页面中的文本选区,可能横跨多个元素。文本选区由用户拖拽鼠标经过文字而产生。
const selection = window.getSelection();
Range对象表示包含节点和部分文本节点的文档片段。通过 selection 对象获得的 range 对象才是我们操作光标的重点。获取 selection ,可以通过全局的 getSelection 方法获取 Range 对象 可以使用 Document.createRange 方法创建 Range。也可以用 Selection 对象的 getRangeAt() 方法或者 Document 对象的 caretRangeFromPoint() 方法获取 Range 对象。
const range = selection.getRangeAt(0);
大致思路就是根据range中的开始节点、相对开始节点的offset和终点节点、相对终点节点的offset,如果是开始标签和终点标签是同个节点或同个父节点用原生surroundContents包裹节点;否则,匹配切割首尾节点及中间节点,逐个替换成包裹节点。
// 获取选区 highlight() { const selection = window.getSelection() if (selection.rangeCount > 0) { const range = selection.getRangeAt(0) const collapsed = range.collapsed const root = range.commonAncestorContainer const snode = range.startContainer const enode = range.endContainer const { startOffset, endOffset } = range; // this.markData.push(this.getRangeOffset(range)) if (snode === enode || snode.parentNode === enode.parentNode) { // 如果是同个父节点或者同个节点,则直接调用原生surroundContents标记 const newnode = this.createEle("font") range.surroundContents(newnode) } else { // 否则调用自定义方法 this.surroundContents(root, range) } // this.markData.push({ snode, enode, startOffset, endOffset }) // console.log(this.markData) } },
surroundContents(root, range) { const selectedNodes = []; const $startNode = range.startContainer; const $endNode = range.endContainer; const { startOffset, endOffset } = range; // 方式二:先将选区内的文本节点拆分并记录,然后将拆分后的文本节点循环匹配,startOffset,使用splitText切割,创建font标签将内容复制生成新节点并替换原节点 let withinSelectedRange = false; const textInfo = this.getTextInfoList() for (let i = 0; i < textInfo.length; i++) { if (textInfo[i][0] === $startNode) { textInfo[i][0].splitText(startOffset) const node = textInfo[i][0].nextSibling selectedNodes.push(node) withinSelectedRange = true } else if (textInfo[i][0] === $endNode) { const node = textInfo[i][0] node.splitText(endOffset) selectedNodes.push(node) break; } else if (withinSelectedRange) { selectedNodes.push(textInfo[i][0]) } } // 方式一:同方法二,只不过没有提前拆分文本节点 // const nodeStack = [root]; // let withinSelectedRange = false; // let curNode = null // while ((curNode = nodeStack.shift())) { // if (curNode.nodeType === 1) { // if (curNode.contains($startNode) || curNode.contains($endNode)) { // nodeStack.unshift(...curNode.childNodes) // } else if (withinSelectedRange) { // nodeStack.unshift(...curNode.childNodes) // } // } else { // if (curNode === $startNode && curNode.nodeType === 3) { // curNode.splitText(startOffset) // const node = curNode.nextSibling // selectedNodes.push(node) // withinSelectedRange = true // } else if (curNode === $endNode && curNode.nodeType === 3) { // const node = curNode // node.splitText(endOffset) // selectedNodes.push(node) // break; // } else if (withinSelectedRange && curNode.nodeType === 3) { // selectedNodes.push(curNode) // } // } // } selectedNodes.map(node => { const $wrap = this.createEle("font"); $wrap.appendChild(node.cloneNode(false)); node.parentNode.replaceChild($wrap, node); }) },
getTextInfoList() { const wrap_dom = document.querySelector("#container"); const txtList = []; const map = function (children) { [...children].forEach(el => { if (el.nodeName === '#text') { txtList.push(el) } else { map(el.childNodes) } }) } // 递归遍历,提取出所有 #text map(wrap_dom.childNodes); const clips = txtList.reduce((arr, item, index) => { const end = item.textContent.length + (arr[index - 1] ? arr[index - 1][2] : 0) arr.push([item, end - item.textContent.length, end]) return arr }, []) return clips },
The text was updated successfully, but these errors were encountered:
No branches or pull requests
选区和范围
Selection
mdn的定义:
用到的方法:
返回选区包含的指定区域(Range)的引用。
一个区域(Range)对象将被加入选区。
将所有的区域都从选区中移除。
Range
mdn的定义:
属性
返回一个表示 Range 的起始位置和终止位置是否相同的布尔值
返回完整包含 startContainer 和 endContainer 的、最深一级的节点
返回包含 Range 终点的节点
返回包含 Range 开始的节点
返回一个表示 Range 终点在 endContainer 中的位置的数字。
返回一个数字,表示 Range 在 startContainer 中的起始位置。
方法
设置 Range 的终点。
设置 Range 的起点
将 Range 中的内容移动到一个新的节点。
高亮标记
大致思路就是根据range中的开始节点、相对开始节点的offset和终点节点、相对终点节点的offset,如果是开始标签和终点标签是同个节点或同个父节点用原生surroundContents包裹节点;否则,匹配切割首尾节点及中间节点,逐个替换成包裹节点。
标记还原(TODO)
The text was updated successfully, but these errors were encountered: