检测在文本中点击了哪个单词

我正在构build一个JS脚本,在某个特定页面上,用户可以单击任何单词并将其存储在一个variables中。

我有一个相当丑陋的解决scheme,涉及使用jQuery进行类parsing:首先parsing整个html,拆分每个空格上的所有内容,然后重新添加包含在<span class="word">word</span>然后我用jQ添加一个事件来检测这样的类的点击,并使用$(this).innerHTML我得到被点击的单词。

这在很多方面都很慢很丑,我希望有人知道另一种方法来实现这一点。

PS:我可能会考虑将它作为浏览器扩展运行,所以如果仅仅是JS,听起来不太可能,而且如果你知道一个允许的浏览器API,可以随意提及它!

一个可能的方式是让用户突出显示单词,而不是单击它,但是我真的很喜欢只需点击一下即可实现同样的function!

下面是一个解决scheme,可以在不添加大量跨度的情况下工作(适用于Webkit,Mozilla和IE9 +):

http://jsfiddle.net/Vap7C/15/

 <p class="clickable">some words</p> $(".clickable").click(function(e) { s = window.getSelection(); var range = s.getRangeAt(0); var node = s.anchorNode; while (range.toString().indexOf(' ') != 0) { range.setStart(node, (range.startOffset - 1)); } range.setStart(node, range.startOffset + 1); do { range.setEnd(node, range.endOffset + 1); } while (range.toString().indexOf(' ') == -1 && range.toString().trim() != '' && range.endOffset < node.length); var str = range.toString().trim(); alert(str); });​ 

在IE8中,由于getSelection有问题。 这个链接( 是否有一个getSelection()的跨浏览器解决scheme? )可能有助于解决这些问题。 我没有在Opera上testing过。

我用一个类似的问题http://jsfiddle.net/Vap7C/1/作为出发点。; 它使用了Selection.modify函数:

 s.modify('extend','forward','word'); s.modify('extend','backward','word'); 

不幸的是,他们并不总是得到全文。 作为一个解决方法,我得到了select的范围 ,并添加了两个循环来查找单词边界。 第一个不断增加字符,直到它到达一个空间。 第二个循环到达单词的末尾,直到到达空间。

这也将抓住单词末尾的任何标点符号,所以如果需要的话,确保你把它修剪掉。

据我所知,为每个单词添加span是唯一的方法来做到这一点。

你可能会考虑使用Lettering.js ,它为你处理分裂 。 虽然这不会影响性能,除非你的“分裂代码”效率低下。

然后,不要将.click()绑定到每个span ,而是将单个.click()绑定到span的容器,并检查event.target来查看哪个span已被单击会更有效。

我所知道的唯一的跨浏览器(IE <8)的方式是在span元素中进行换行。 这是丑陋的,但不是很慢。

这个例子是直接从jQuery .css()函数文档中获得的,但是有一大块文本需要预处理:

http://jsfiddle.net/kMvYy/

这是另一种方法(在这里给出: jquery捕获字的值 )在同一个文本块,不需要包装spanhttp://jsfiddle.net/Vap7C/1

这个怎么样? 它使用getSelection()绑定到mouseup

 <script type="text/javascript" src="jquery-1.6.3.min.js"></script> <script> $(document).ready(function(){ words = []; $("#myId").bind("mouseup",function(){ word = window.getSelection().toString(); if(word != ''){ if( confirm("Add *"+word+"* to array?") ){words.push(word);} } }); //just to see what we've got $('button').click(function(){alert(words);}); }); </script> <div id='myId'> Some random text in here with many words huh </div> <button>See content</button> 

我想不出分裂的方式,这是我会做的,一个小的插件,将分裂成spans ,当点击它将其内容添加到一个array进一步使用:

 <script type="text/javascript" src="jquery-1.6.3.min.js"></script> <script> //plugin, take it to another file (function( $ ){ $.fn.splitWords = function(ary) { this.html('<span>'+this.html().split(' ').join('</span> <span>')+'</span>'); this.children('span').click(function(){ $(this).css("background-color","#C0DEED"); ary.push($(this).html()); }); }; })( jQuery ); //plugin, take it to another file $(document).ready(function(){ var clicked_words = []; $('#myId').splitWords(clicked_words); //just to see what we've stored $('button').click(function(){alert(clicked_words);}); }); </script> <div id='myId'> Some random text in here with many words huh </div> <button>See content</button> 

像这样获取用户select的文本与jQuery和它的用途 ?

这是一个完全不同的方法。 我不确定它的实用性,但它可能会给你一些不同的想法。 这是我在想什么,如果你有一个容器标签的位置相对与其中只是文本。 然后,您可以在每个单词旁边放置一个跨度logging其高度,宽度,左侧和顶部的偏移量,然后删除跨度。 将这些保存到数组中,然后在该区域中进行单击时,执行search以找出最接近单击的单词。 这显然会在一开始就是密集的。 所以在这个人会花一些时间阅读文章的情况下,这个效果最好。 好处是你不必担心可能有100多个额外的元素,但是这个好处可能是最好的。

注意我认为你可以从DOM中删除容器元素来加速过程,仍然可以获得偏移距离,但是我并不积极。

以下是接受的答案的改进:

 $(".clickable").click(function (e) { var selection = window.getSelection(); if (!selection || selection.rangeCount < 1) return true; var range = selection.getRangeAt(0); var node = selection.anchorNode; var word_regexp = /^\w*$/; // Extend the range backward until it matches word beginning while ((range.startOffset > 0) && range.toString().match(word_regexp)) { range.setStart(node, (range.startOffset - 1)); } // Restore the valid word match after overshooting if (!range.toString().match(word_regexp)) { range.setStart(node, range.startOffset + 1); } // Extend the range forward until it matches word ending while ((range.endOffset < node.length) && range.toString().match(word_regexp)) { range.setEnd(node, range.endOffset + 1); } // Restore the valid word match after overshooting if (!range.toString().match(word_regexp)) { range.setEnd(node, range.endOffset - 1); } var word = range.toString(); });​