


How to get the sentence where the selected text is located using Javascript
这篇文章主要给大家爱介绍了关于利用Javascript获取选择文本所在的句子的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起看看吧。
前言
最近收到一个 issue 期望能在划词的时候同时保存单词的上下文和来源网址。这个功能其实很久之前就想过,但感觉不好实现一直拖延没做。真做完发现其实并不复杂,完整代码在这里,或者继续往下阅读分析。话不多说了,来一起看看详细的介绍吧。
原理分析
获取选择文本
通过 window.getSelection()
即可获得一个 Selection 对象,再利用 .toString()
即可获得选择的文本。
锚节点与焦节点
在 Selection 对象中还保存了两个重要信息,anchorNode 和 focusNode,分别代表选择产生那一刻的节点和选择结束时的节点,而 anchorOffset 和 focusOffset 则保存了选择在这两个节点里的偏移值。
这时你可能马上就想到第一个方案:这不就好办了么,有了首尾节点和偏移,就可以获取句子的头部和尾部,再把选择文本作为中间,整个句子不就出来了么。
当然不会这么简单哈stuck_out_tongue。
强调一下
一般情况下,anchorNode 和 focusNode 都是 Text 节点(而且因为这里处理的是文本,所以其它情况也会直接忽略),可以考虑这种情况:
<strong>Saladict</strong> is awesome!
如果选择的是“awesome”,那么 anchorNode 和 focusNode 都是 is awesome!,所以取不到前面的 “Saladict”。
另外还有嵌套的情况,也是同样的问题。
Saladict is <strong><a href="#" rel="external nofollow" >awesome</a></strong>!
所以我们还需要遍历兄弟和父节点来获取完整的句子。
遍历到哪?
于是接下就是解决遍历边界的问题了。遍历到什么地方为止呢?我的判断标准是:跳过 inline-level 元素,遇到 block-level 元素为止。而判断一个元素是 inline-level 还是 block-level 最准确的方式应该是用 window.getComputedStyle()
。但我认为这么做太重了,也不需要严格的准确性,所以用了常见的 inline 标签来判断。
const INLINE_TAGS = new Set([ // Inline text semantics 'a', 'abbr', 'b', 'bdi', 'bdo', 'br', 'cite', 'code', 'data', 'dfn', 'em', 'i', 'kbd', 'mark', 'q', 'rp', 'rt', 'rtc', 'ruby', 's', 'samp', 'small', 'span', 'strong', 'sub', 'sup', 'time', 'u', 'var', 'wbr' ])
原理总结
句子由三块组成,选择文本作为中间,然后遍历兄弟和父节点获取首尾补上。
实现
选择文本
先获取文本,如果没有则退出
const selection = window.getSelection() const selectedText = selection.toString() if (!selectedText.trim()) { return '' }
获取首部
对于 anchorNode 只考虑 Text 节点,通过 anchorOffset 获取选择在 anchorNode 的前半段内容。
然后开始补全在 anchorNode 之前的兄弟节点,最后补全在 anchorNode 父元素之前的兄弟元素。注意后面是元素,这样可以减少遍历的次数,而且考虑到一些被隐藏的内容不需要获取,用 innerText 而不是 textContent 属性。
let sentenceHead = '' const anchorNode = selection.anchorNode if (anchorNode.nodeType === Node.TEXT_NODE) { let leadingText = anchorNode.textContent.slice(0, selection.anchorOffset) for (let node = anchorNode.previousSibling; node; node = node.previousSibling) { if (node.nodeType === Node.TEXT_NODE) { leadingText = node.textContent + leadingText } else if (node.nodeType === Node.ELEMENT_NODE) { leadingText = node.innerText + leadingText } } for ( let element = anchorNode.parentElement; element && INLINE_TAGS.has(element.tagName.toLowerCase()) && element !== document.body; element = element.parentElement ) { for (let el = element.previousElementSibling; el; el = el.previousElementSibling) { leadingText = el.innerText + leadingText } } sentenceHead = (leadingText.match(sentenceHeadTester) || [''])[0] }
最后从提取句子首部用的正则是这个
// match head a.b is ok chars that ends a sentence const sentenceHeadTester = /((\.(?![ .]))|[^.?!。?!…\r\n])+$/
前面的 ((\.(?![ .])) 主要是为了跳过 a.b 这样的特别是在技术文章中常见的写法。
获取尾部
跟首部同理,换成往后遍历。最后的正则保留了标点符号
// match tail for "..." const sentenceTailTester = /^((\.(?![ .]))|[^.?!。?!…\r\n])+(.)\3{0,2}/
压缩换行
拼凑完句子之后压缩多个换行为一个空白行,以及删除每行开头结尾的空白符
return (sentenceHead + selectedText + sentenceTail) .replace(/(^\s+)|(\s+$)/gm, '\n') // allow one empty line & trim each line .replace(/(^\s+)|(\s+$)/g, '') // remove heading or tailing \n
完整代码
const INLINE_TAGS = new Set([ // Inline text semantics 'a', 'abbr', 'b', 'bdi', 'bdo', 'br', 'cite', 'code', 'data', 'dfn', 'em', 'i', 'kbd', 'mark', 'q', 'rp', 'rt', 'rtc', 'ruby', 's', 'samp', 'small', 'span', 'strong', 'sub', 'sup', 'time', 'u', 'var', 'wbr' ]) /** * @returns {string} */ export function getSelectionSentence () { const selection = window.getSelection() const selectedText = selection.toString() if (!selectedText.trim()) { return '' } var sentenceHead = '' var sentenceTail = '' const anchorNode = selection.anchorNode if (anchorNode.nodeType === Node.TEXT_NODE) { let leadingText = anchorNode.textContent.slice(0, selection.anchorOffset) for (let node = anchorNode.previousSibling; node; node = node.previousSibling) { if (node.nodeType === Node.TEXT_NODE) { leadingText = node.textContent + leadingText } else if (node.nodeType === Node.ELEMENT_NODE) { leadingText = node.innerText + leadingText } } for ( let element = anchorNode.parentElement; element && INLINE_TAGS.has(element.tagName.toLowerCase()) && element !== document.body; element = element.parentElement ) { for (let el = element.previousElementSibling; el; el = el.previousElementSibling) { leadingText = el.innerText + leadingText } } sentenceHead = (leadingText.match(sentenceHeadTester) || [''])[0] } const focusNode = selection.focusNode if (selection.focusNode.nodeType === Node.TEXT_NODE) { let tailingText = selection.focusNode.textContent.slice(selection.focusOffset) for (let node = focusNode.nextSibling; node; node = node.nextSibling) { if (node.nodeType === Node.TEXT_NODE) { tailingText += node.textContent } else if (node.nodeType === Node.ELEMENT_NODE) { tailingText += node.innerText } } for ( let element = focusNode.parentElement; element && INLINE_TAGS.has(element.tagName.toLowerCase()) && element !== document.body; element = element.parentElement ) { for (let el = element.nextElementSibling; el; el = el.nextElementSibling) { tailingText += el.innerText } } sentenceTail = (tailingText.match(sentenceTailTester) || [''])[0] } return (sentenceHead + selectedText + sentenceTail) .replace(/(^\s+)|(\s+$)/gm, '\n') // allow one empty line & trim each line .replace(/(^\s+)|(\s+$)/g, '') // remove heading or tailing \n }
上面是我整理给大家的,希望今后会对大家有帮助。
相关文章:
The above is the detailed content of How to get the sentence where the selected text is located using Javascript. For more information, please follow other related articles on the PHP Chinese website!

JavaScript's application in the real world includes front-end and back-end development. 1) Display front-end applications by building a TODO list application, involving DOM operations and event processing. 2) Build RESTfulAPI through Node.js and Express to demonstrate back-end applications.

The main uses of JavaScript in web development include client interaction, form verification and asynchronous communication. 1) Dynamic content update and user interaction through DOM operations; 2) Client verification is carried out before the user submits data to improve the user experience; 3) Refreshless communication with the server is achieved through AJAX technology.

Understanding how JavaScript engine works internally is important to developers because it helps write more efficient code and understand performance bottlenecks and optimization strategies. 1) The engine's workflow includes three stages: parsing, compiling and execution; 2) During the execution process, the engine will perform dynamic optimization, such as inline cache and hidden classes; 3) Best practices include avoiding global variables, optimizing loops, using const and lets, and avoiding excessive use of closures.

Python is more suitable for beginners, with a smooth learning curve and concise syntax; JavaScript is suitable for front-end development, with a steep learning curve and flexible syntax. 1. Python syntax is intuitive and suitable for data science and back-end development. 2. JavaScript is flexible and widely used in front-end and server-side programming.

Python and JavaScript have their own advantages and disadvantages in terms of community, libraries and resources. 1) The Python community is friendly and suitable for beginners, but the front-end development resources are not as rich as JavaScript. 2) Python is powerful in data science and machine learning libraries, while JavaScript is better in front-end development libraries and frameworks. 3) Both have rich learning resources, but Python is suitable for starting with official documents, while JavaScript is better with MDNWebDocs. The choice should be based on project needs and personal interests.

The shift from C/C to JavaScript requires adapting to dynamic typing, garbage collection and asynchronous programming. 1) C/C is a statically typed language that requires manual memory management, while JavaScript is dynamically typed and garbage collection is automatically processed. 2) C/C needs to be compiled into machine code, while JavaScript is an interpreted language. 3) JavaScript introduces concepts such as closures, prototype chains and Promise, which enhances flexibility and asynchronous programming capabilities.

Different JavaScript engines have different effects when parsing and executing JavaScript code, because the implementation principles and optimization strategies of each engine differ. 1. Lexical analysis: convert source code into lexical unit. 2. Grammar analysis: Generate an abstract syntax tree. 3. Optimization and compilation: Generate machine code through the JIT compiler. 4. Execute: Run the machine code. V8 engine optimizes through instant compilation and hidden class, SpiderMonkey uses a type inference system, resulting in different performance performance on the same code.

JavaScript's applications in the real world include server-side programming, mobile application development and Internet of Things control: 1. Server-side programming is realized through Node.js, suitable for high concurrent request processing. 2. Mobile application development is carried out through ReactNative and supports cross-platform deployment. 3. Used for IoT device control through Johnny-Five library, suitable for hardware interaction.


Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

AI Hentai Generator
Generate AI Hentai for free.

Hot Article

Hot Tools

Dreamweaver Mac version
Visual web development tools

mPDF
mPDF is a PHP library that can generate PDF files from UTF-8 encoded HTML. The original author, Ian Back, wrote mPDF to output PDF files "on the fly" from his website and handle different languages. It is slower than original scripts like HTML2FPDF and produces larger files when using Unicode fonts, but supports CSS styles etc. and has a lot of enhancements. Supports almost all languages, including RTL (Arabic and Hebrew) and CJK (Chinese, Japanese and Korean). Supports nested block-level elements (such as P, DIV),

SublimeText3 Chinese version
Chinese version, very easy to use

WebStorm Mac version
Useful JavaScript development tools

MinGW - Minimalist GNU for Windows
This project is in the process of being migrated to osdn.net/projects/mingw, you can continue to follow us there. MinGW: A native Windows port of the GNU Compiler Collection (GCC), freely distributable import libraries and header files for building native Windows applications; includes extensions to the MSVC runtime to support C99 functionality. All MinGW software can run on 64-bit Windows platforms.