悬停时在文本块中突出显示单个单词

20
在javascript/jQuery中,是否有一种方法可以识别文本块/段落中的单词?例如,假设我有以下段落:

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris suscipit interdum fermentum. Aenean fermentum imperdiet augue, et venenatis lectus semper vel. Phasellus faucibus nulla in quam egestas eleifend. Cras tristique augue eget libero tristique condimentum. Mauris eget diam eget risus feugiat rutrum. Duis placerat lorem quis augue semper porttitor. Nullam iaculis dui feugiat erat condimentum rutrum. Sed at accumsan diam. Maecenas ut urna id velit posuere auctor in vel dui. Aenean consectetur dui in leo faucibus sed feugiat dui blandit. In accumsan diam vitae erat volutpat volutpat aliquam nunc euismod. Vivamus viverra lorem nulla. Quisque justo quam, adipiscing sit amet auctor non, laoreet sit amet nisl. Donec euismod lorem ac mi dictum volutpat. Donec ligula mi, varius ac auctor at, sollicitudin id elit. In auctor sodales ipsum nec consectetur. Sed lacinia varius nibh vitae vulputate.

如果当鼠标悬停在第一个单词“Lorem”上方时,我希望它变成粗体(例如)。基本上,我希望只有鼠标悬停在其上的文本才添加CSS属性,然后在鼠标不再悬停在该单词上时删除该CSS属性。
我唯一能想到的方法是在每个单词之间添加一个标签。这是唯一的方法吗?或者,可能有一种更有效率的方法吗?或者,jQuery的mouseover事件只能在标签内部起作用吗?它可以用于识别文本块吗?

3
这是唯一的方式吗?是的,基本上是这样。也许有更高效的方式吗?不是真的......你不能仅仅从文本节点中选出一个单词并立即对其进行样式设置。jQuery 的 mouseover 事件只能在标签内部生效吗?它能在识别文本块时生效吗?不行。它可以在任何元素上生效,而不是元素的部分。 - Joseph Marikle
1
你可能想要研究一下 Lettering.js 插件,因为它是专门设计来使你正在做的事情变得更加容易。 - Pointy
假设该方法保留并且浏览器开始实现它,那么在大约4年后,当caretPositionFromPoint()规范不再是草案时,您将能够使用它。 - mercator
此外,这个问题讨论了使用JavaScript查找光标下的单词的方法:https://dev59.com/bXE95IYBdhLWcg3wHqWl - Anderson Green
6个回答

20
这似乎是一个适合使用http://letteringjs.com/的好任务。您可以设置它在单词边界处为您创建跨度。JSFiddle与您的示例:http://jsfiddle.net/3HdKH/。从他们的教程中了解更多:https://github.com/davatron5000/Lettering.js/wiki/Wrapping-words-with-lettering%28%27words%27%29。使用:
$(document).ready(function() {
  $(".word_split").lettering('words');
});

这是一个HTML标签。
<p class="word_split">Don't break my heart.</p>

Becomes:

<p class="word_split">
  <span class="word1">Don't</span>
  <span class="word2">break</span>
  <span class="word3">my</span>
  <span class="word4">heart.</span>
</p>

然后你可以使用以下CSS:
.word_split span:hover {
    font-weight:bold;
}

3
最好的方法确实是...但要注意开发者的警告(针对原帖作者):“聪明一点,使用得当。如果你试图在页面上每个字母都用span标签包裹起来,你很可能会破坏你的浏览器”。 - Gabriele Petrioli
鼠标悬停时是否可以突出显示单个字母(而不是单词)? - Anderson Green
@Davy,我有一些基于JavaScript逻辑输出到屏幕上的文本...它是通过$('#npc_dialog_dictionary_chinese').html(dialog_text);更新的...我尝试使用他的函数$("#npc_dialog_dictionary_chinese").lettering('words');,但它对输出的文本无效...你知道为什么吗? - user3871
我正在尝试对每个字符应用相同的效果,但文本中有一些链接。但我找不到任何解决方案。 - Muhammad Shahid

3

以下是我使用的一种技术,它会在父元素中的所有单词周围添加 span 标签,以便在悬停时可以高亮显示:

const parentElement = document.getElementById('parent');

parentElement.onmouseover = e => {
  e.target.innerHTML = e.target.innerText.replace(/([\w]+)/g, '<span>$1</span>');
};
p#parent span:hover {
  background: yellow;
  cursor: pointer;
}
<p id="parent">One morning, when Gregor Samsa woke from troubled dreams, he found himself transformed in his bed into a horrible vermin. He lay on his armour-like back, and if he lifted his head a little he could see his brown belly, slightly domed and divided by arches into stiff sections. The bedding was hardly able to cover it and seemed ready to slide off any moment. His many legs, pitifully thin compared with the size of the rest of him, waved about helplessly as he looked. "What's happened to me?" he thought. It wasn't a dream. His room, a proper human room although a little too small, lay peacefully between its four familiar walls. A collection of textile samples lay spread out on the table - Samsa was a travelling salesman - and above it there hung a picture that he had recently cut out of an illustrated magazine and housed in a nice, gilded frame. It showed a lady fitted out with a fur hat and fur boa who sat upright, raising a heavy fur muff that covered the whole of her lower arm towards the viewer. Gregor then turned to look out the window at the dull weather. </p>

这段代码为列表项中的单词添加了一个点击处理程序:
parentElement.onmouseover = e => {
  if (e.target.nodeName === 'LI') {
    e.target.innerHTML = 
      e.target.innerText.replace(/([\w]+)/g, '<span>$1</span>');
    e.target.onclick = e => {
      doSomething(e.target.textContent);
    };
  }
}

嗨,如果我想使用文本中的每个字母,正则表达式会是什么样子? - Abel Agoi

1
$("p:contains(Lorem)").each(function(){
  $(this).html($(this).text().replace(/(Lorem)/, '<span class="highlightWord">$1</span> '));
});

这是从这里获取的


你怎么知道哪个单词被高亮了? - Tom Squires
@Tom Squires,我们搞定了...必须修复一些东西。你会知道的,因为你已经将一个类应用到它上面了。该类将在你的CSS中定义为 font-weight: bold; - Joseph Marikle

1
$('span').each(function(){
    $(this).html(
            $(this)
                .text()
                .split(' ')
                .map(function(x){return "<word>"+x+"</word>";})
                .join(' ')
       )
});
$('word').hover(function(){
        $(this).css(/*highlight*/);            
},function(){
        $(this).css(/*de-highlight*/);   
});

0
唯一的方法是使用跨度(如您所述)。除非将其分解,否则Javascript将文本块视为一个元素。您只能在元素上执行操作。由于所有文本都流动且没有位置,因此您无法确定单个单词位置以查看其何时悬停。除非您的文本非常庞大,否则添加几个额外的跨度断点对性能不会造成太大影响。

0

那是我能想到的唯一方法。你可能可以使用鼠标事件和鼠标位置来做些什么(尝试找出位置上的单词),但这不是最有趣的尝试。你可能需要在单词周围添加一些标签作为参考点。

如果你要将其分解成元素,我建议使用单个字符标签,例如<p>

另一个中间选项是只在容器上使用悬停事件,并且仅在用户悬停时将文本分成子元素。类似于:

$('#container').live('mouseenter',function(){
var jThis = $(this);
var text = jThis.text();
jThis.attr('original',text);
text = text.split(' ');
var out_text = '';
for(var nI = 0; nI < text.length; nI++){
out_text += "<p>"+text[nI]+"</p>";
}
jThis.html(out_text);
});
$('#container p').live('mouseenter',function(){
$(this).addClass('highlight');
});

你需要添加输出事件。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接