3

HTMLドキュメントのどこかでマウスクリックが発生したときに通知するイベントリスナーを設定できます。ただし、一部のテキストでクリックが発生した場合は、テキスト内のどの文字でクリックが発生したかを知る必要があります。これを行う方法はありますか?

私はいくつかの本当に不快な解決策を考えることができます。たとえば、ドキュメント内のすべての文字について、独自のイベントを使用して個別の要素でラップすることができます。または、クリックが発生したテキストノードがわかるので、おそらくclientWidthを使用して、何らかの計算(基本的にはテキストのレンダリングのシミュレーションとほぼ同じ)を実行して、クリックが発生した文字を判別できます。

確かにもっと簡単なものがあるに違いありませんか?

4

4 に答える 4

8

マウスイベントがキャプチャされたら、要素内のテキストを2つの別々のスパンに分割します。各スパンのオフセットを調べて、発生したイベントを判別します。次に、そのスパンを2つに分割し、再度比較します。座標にマウスクリックの座標が含まれる単一の文字を持つスパンができるまで繰り返します。これは本質的に二分探索であるため、このプロセス全体はかなり高速であり、スパンの総数は他の方法と比較して少なくなります。文字が見つかると、スパンを解消して、すべてのテキストを元の要素に戻すことができます。

于 2012-08-02T04:26:10.577 に答える
2

残念ながら、要素内のすべての文字をラップする必要がありますが、各文字にイベントリスナーをアタッチする必要はありません。clickイベントが要素で発生すると、その親にバブルされます。target次に、イベントのプロパティを使用して、実際にクリックされた要素を取得できます。

。という名前の要素にテキストがあるとしtextElementます。span各文字のが含まれています。文字をクリックして削除できるようにしたい場合は、次のコードを使用できます。

textElement.addEventListener('click', function(e) {
    textElement.removeChild(e.target);
}, false);

やってみよう。

于 2012-08-01T04:01:44.410 に答える
1

これは、マイケルが彼の答えに書いたことを実装するための私の努力です:

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
}
于 2019-03-30T09:47:22.483 に答える
0

ドキュメントモデルオブジェクトに各文字を配置することは、思ったほど不快ではありません。HTML解析、DOM表現、およびイベント処理は、最新のブラウザーでのメモリーと処理の点で非常に効率的です。同様のメカニズムが低レベルで使用され、文字もレンダリングされます。ブラウザがそのレベルで何をするかをシミュレートするには、多くの作業が必要です。

  • ほとんどのドキュメントは可変幅の文字で構成されています
  • ラッピングは、さまざまな方法で正当化または調整できます
  • 文字とバイトの間に1対1のマッピングはありません
  • 真に国際化された堅牢なソリューションであるためには、サロゲートペアもサポートされている必要があります1

この例は軽量で、読み込みが速く、一般的なブラウザ間で移植可能です。その優雅さはすぐにはわかりません。国際的なキャラクターとイベントリスナーの間に1対1の対応を確立することで、多くの信頼性が得られます。

  <!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'>&#xE6;&#x20AC; &ndash; &#xFD7;&#xD8; &mdash;</p>
      <p id='p1'>Next  E para.</p>
      <p id='p2'>&copy; 2017</p>
      <hr>
      <p id='result'>&nbsp;</p>
  </body>
  </html>

[1]この単純な例にはサロゲートペアの処理はありませんが、iループの本体に追加することができます。

于 2017-02-08T04:39:08.650 に答える