我可以设置一个事件监听器来告诉我何时在HTML文档中的某个位置发生鼠标点击。但是如果在某些文本上发生了点击,我需要知道文本中的哪个字符发生了点击。有没有办法做到这一点?
我可以想到一些非常令人讨厌的解决方案。例如,对于文档中的每个单个字符,我可以将其包装在具有自己的事件的单独元素中。或者,因为我可以告诉发生了哪个文本节点,我可以使用clientWidth执行某种计算(基本上就像模拟文本的渲染),以确定点击发生在哪个字符。
肯定会有更容易的事情吗?
答案 0 :(得分:8)
捕获鼠标事件后,将元素中的文本拆分为两个单独的跨度。查看每个跨度的偏移量以确定事件发生的位置。现在将该跨度拆分为两个并再次进行比较。重复,直到您的跨度具有单个字符,其坐标包含鼠标单击的坐标。由于这实际上是二元搜索,因此整个过程相当快,并且与替代方案相比,跨度总数较低。找到角色后,可以解散跨距,并将所有文本返回到原始元素。
答案 1 :(得分:2)
不幸的是,你必须将每个字符包装在一个元素中,但是你不必为每个字符附加一个事件监听器。当对元素触发click
事件时,它会冒泡到其父元素。然后,您可以使用事件的target
属性检索实际单击的元素。
假设我们在名为textElement
的元素中有一些文字。它包含每个字符span
。如果我们想要点击字符来删除它们,我们可以使用以下代码:
textElement.addEventListener('click', function(e) {
textElement.removeChild(e.target);
}, false);
<强> Try it out. 强>
答案 2 :(得分:0)
将每个角色放置在文档模型对象中并不像听起来那样令人讨厌。 HTML解析,DOM表示和事件处理在现代浏览器中的内存和处理方面非常有效。在较低级别使用类似的机制来渲染字符。模拟浏览器在该级别执行的操作需要做很多工作。
此示例轻量级,加载速度快,可在常见浏览器中移植。它的优雅并不是立竿见影的,通过在国际角色和事件听众之间建立一对一的对应关系,可以获得很大的可靠性。
<!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) {
cc = from.charAt(i);
to = to + pre + i + inf + cc + 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'>æ€ – ࿗Ø —</p>
<p id='p1'>Next E para.</p>
<p id='p2'>© 2017</p>
<hr>
<p id='result'> </p>
</body>
</html>
[1]这个简单的例子没有代理对的处理,但是可以在i循环的主体中添加。
答案 3 :(得分:0)
这是我努力实现迈克尔在他的answer中所写的内容:
function hitCharBinSearch(mClientX, inmostHitEl) {
const originalInmost = inmostHitEl
const bareText = inmostHitEl.firstChild.textContent
var textNode = inmostHitEl.firstChild
var textLenghtBeforeHit = 0
do {
let textNodeR = textNode.splitText(textNode.length / 2)
let textNodeL = textNode
let spanL = document.createElement('span')
spanL.appendChild(textNodeL)
let spanR = document.createElement('span')
spanR.appendChild(textNodeR)
inmostHitEl.appendChild(spanL)
inmostHitEl.appendChild(spanR)
if (mClientX >= spanR.getBoundingClientRect().left) {
textNode = textNodeR
inmostHitEl = spanR
textLenghtBeforeHit += textNodeL.length
}
else {
textNode = textNodeL
inmostHitEl = spanL
}
} while (textNode.length > 1)
/* This is for proper caret simulation. Can be omitted */
var rect = inmostHitEl.getBoundingClientRect()
if (mClientX >= (rect.left + rect.width / 2))
textLenghtBeforeHit++
/*******************************************************/
originalInmost.innerHTML = bareText
return textLenghtBeforeHit
}