我有一个HTML元素,里面只有可见文字。此示例是<div>
元素,但它可以是<span>
,<p>
或其他DOM元素。
<div>This is a simple example.</div>
单击时,我可以将光标的位置放在div的表面上,但是我需要在单击时确定最近的字符和/或其索引在div.innerHTML字符串中的位置。
我在SVG文本实体here中的“getCharNumAtPosition”方法中找到了类似的实现。
是否可以在JavaScript中使用HTML实现这样的功能?
(如果解决方案可以在大多数现代浏览器中移植,使用大多数书面语言,并且基于相对稳定的标准,以便以后不会出现错误,那么解决方案将非常有用。)
答案 0 :(得分:11)
$('div').click( function () {
getSelectionPosition ();
});
function getSelectionPosition () {
var selection = window.getSelection();
console.log(selection.focusNode.data[selection.focusOffset]);
alert(selection.focusOffset);
}
这适用于“点击”,以及大多数浏览器的“范围”。 (selection.type = "caret"
/ selection.type = "range"
)。
selection.focusOffset()
为您提供内部节点中的位置。如果元素是嵌套的,例如在<b>
或<span>
标记内,它将为您提供内部元素内的位置,而不是全文,或多或少。我无法“选择”带有focusOffset
和“插入符号”类型的子标记的第一个字母(单击,而不是范围选择)。当您单击第一个字母时,它会在标记开头加1之前给出最后一个元素的位置。当您单击第二个字母时,它会正确地为您提供“1”。但我没有找到一种方法来访问子元素的第一个元素(偏移0)。这个“选择/范围”的东西看起来很麻烦(或者对我来说非常不直观)。 ^^
但是没有嵌套元素的使用非常简单! (适用于您的<div>
)
这个答案在被接受时会有效,但不会再出现,原因如下。其他答案现在最有用。
Firefox和Chrome都调试了window.getSelection()
行为。可悲的是,这个用例现在没用了。 (阅读文档,IE 9及更高版本的行为应相同)。
现在,字符的中间部分用于确定偏移量。这意味着单击一个角色可以返回2个结果。第一个字符为0或1,第二个字符为1或2,等等。
我更新了JSFiddle example。
请注意,如果您调整窗口大小( Ctrl +鼠标),则Chrome上的行为非常糟糕,只需点击一下。
答案 1 :(得分:2)
您可以使用JavaScript将每个字符分解为自己的SPAN标记,并为每个字符添加onclick事件。然后,在单击SPAN时从事件数据中读取x,y位置。
同样,您可以访问使用event.target.innerHTML
点击的角色答案 2 :(得分:1)
此示例可快速加载适中大小的文本块,可移植且可靠。虽然它的优雅并不是很明显,但可靠性在于在国际角色和DOM事件监听器 1 之间建立简单的一对一的对应关系。
最好只依赖广泛采用的字符编码,DOM和ECMA标准,如本例所示。其他方法通常依赖于低级事件目标属性或函数,如getSelection(),它们既不是稳定的,也不是可移植的浏览器和语言 2 。
可以通过多种方式修改示例代码以用于特定应用程序。例如,可以使用其他机制来选择为charClick回调初始化哪些DOM对象。也可以在i循环中支持代理对。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Character Click Demo</title>
<script type='text/javascript'>
var pre = "<div onclick='charClick(this, ";
var inf = ")'>";
var suf = "</div>";
function charClick(el, i) {
var p = el.parentNode.id;
var s = "para '" + p + "' idx " + i + " click";
ele = document.getElementById('result');
ele.innerHTML = s; }
function initCharClick(ids) {
var el; var from; var length; var to; var cc;
var idArray = ids.split(" ");
var idQty = idArray.length;
for (var j = 0; j < idQty; ++ j) {
el = document.getElementById(idArray[j]);
from = unescape(el.innerHTML);
length = from.length;
to = "";
for (var i = 0; i < length; ++ i) {
to = to + pre + i + inf + from.charAt(i) + suf;
el.innerHTML = to; } }
</script>
<style>
.characters div {
padding: 0;
margin: 0;
display: inline }
</style>
</head>
<body class='characters' onload='initCharClick("h1 p0 p2")'>
<h1 id='h1'>Character Click Demo</h1>
<p id='p0'>Test æ€ – ࿗Ø — string.</p>
<p id='p1'>Next E para.</p>
<p id='p2'>© 2017</p>
<hr>
<p id='result'> </p>
</body>
</html>
在国际化生产场景中使用此功能之前,建议进行全面测试。如果发现错误,请建议编辑或添加注释,以便添加优化。
备注强>
[1]这些事件监听器可以直接添加,但是需要分支浏览器的可移植性或者为这个用例添加特定速度或便利值的库的额外权重。
[2]请参阅W3C's UI events page中有关选择事件的说明。
答案 3 :(得分:1)
在许多情况下,可能的解决方案是在标签内容的每个字符之间添加零宽度空格字符(U + 200B)。然后使用javascript window.getSelection().focusOffset
+一些简单的计算即可完成工作。
示例html代码(包括零宽度空格字符):
<div onclick='magic(this)'>This is a simple example.</div>
示例javascript代码:
<script>
function magic(e)
{
var s, p, c;
s = e.innerHTML;
p = window.getSelection().focusOffset;
c = s.charAt((p >> 1) << 1);
alert("index:" + (p >> 1) + " char: " + c);
}
</script>
即使在Internet Explorer上,似乎也可以广泛使用!
jsFidle:http://jsfiddle.net/by1a9pfm/