记录--前端实现点击选词功能
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助
今天有一个需求,点击选中某个英文单词,然后对这个单词做一些处理,例如高亮背景、查看一些详细信息等等,今天简单实现了一下,效果如下:(支持移动端,chrome和sarafi浏览器均能正常使用。语言🚀 vue3 + typescript)
选词
由于要动态添加给某些单词动态添加一些标签,我们这里可以考虑使用v-html
。
首先我们先编写一下简单的结构
<script setup lang="ts"> </script> <template> <div class="container" v-html="shortArticle"></div> </template> <style> .container { font-size: 18px; } </style>
然后,我们将需要处理的短文变换为span
标签包裹,这里的思路是按照空格划分,然后添加span
结构,最后拼接到一起返回。这里有一些边缘条件要考虑,比如can't
、(which
、yes!
等等,按照空格划分出来的数据有一点问题。
如果不做处理的话,一些标点符号也会高亮出来,就不太正确了。下面是处理逻辑,整体比较简单,就不解释了。
function addElementSpan(str: string): string { return str .split(' ') .map((item) => { const { start, word, end } = getWord(item) return `${start}<span>${word}</span>${end} ` }) .join('') } function getWord(str: string) { let word = '' let start = '' let end = '' let j = str.length - 1 let i = 0 while (i < str.length) { if (/^[a-zA-Z]$/.test(str[i])) { break } start = start + str[i] i += 1 } while (j >= 0) { if (/^[a-zA-Z]$/.test(str[j])) { break } end = str[j] + end j -= 1 } word = str.slice(i, j + 1) // 处理数字 if (!word && start === end) { start = '' } return { start, word, end } }
现在我们来实现效果
<script setup lang="ts"> import { computed } from 'vue' import { addElementSpan } from './utils' const str = `It works fine if you move the navbar outside the header. See below. For the reason, according to MDN: The element is positioned according to the normal flow of the document, and then offset relative to its flow root and containing block based on the values of top, right, bottom, and left. For the containing block: The containing block is the ancestor to which the element is relatively positioned So, when I do not misunderstand, the navbar is positioned at offset 0 within the header as soon as it is scrolled outside the viewport (which, clearly, means, you can't see it anymore).` const shortArticle = computed(() => { return addElementSpan(str) }) function setColor(event: any) { // console.log(event.target.innerText) 获取选中的文本 event.target?.classList.add('word_highlight') } </script> <template> <div class="container" @click="setColor($event)" v-html="shortArticle"></div> </template> <style> .word_highlight { background-color: red; } </style>
在父亲元素上添加点击事件,触发事件点击之后,调用setColor
函数,高亮背景(添加class)
不过有一点小小的问题,点击div
的空白区域或者非英文单词区域会直接整个背景变成红色,控制台打印event.target.innerText
可以发现它的值为整个文本,所以我们可以根据判断打印的文本长度和需要设置的文本长度是否一致来解决这个问题。(ps:⬆️面的示例代码str
字符串使用了反引号 模板字符串 ,直接使用下面会影响结果)
function setColor(event: any) { // console.log(event.target.innerText) if(str !== event.target.innerText){ event.target?.classList.add('word_highlight') } }
对于event.target
不太了解的伙伴可以看这篇文章 ➡️ Event.target - Web API 接口参考 | MDN (mozilla.org)
(和event.target
类似的还有一个属性event.currentTarget
,不太了解的伙伴可以看下这篇文章 ➡️ Event.currentTarget - Web API 接口参考 | MDN (mozilla.org),它俩的区别是event.target
指的是事件触发的元素,而event.currentTarget
指的是事件绑定的元素)
功能拓展
这里只是演示了一下比较简单的背景高亮效果,有需求的伙伴可以自己拓展一下。
比如类似于掘金的拼写错误提示框
如果要实现滑动选词的话,可以参考这个博主的文章 ➡️ 鼠标选中文本划词高亮、再次选中划词取消高亮效果