Determine the position index of a character within an HTML element when clicked

后端 未结 4 1609
误落风尘
误落风尘 2020-12-09 09:49

I have an HTML element with only visible text inside. This example is a

element, but it could be a ,

相关标签:
4条回答
  • This example is quick loading for moderately sized blocks of text, portable, and robust. Although its elegance is not immediately apparent, reliability lies in the creation of a simple one to one correspondence between international characters and DOM event listeners 1.

    It is best to relying only on widely adopted character encoding, DOM, and ECMA standards as in this example. Other approaches often rely on low level event target attributes or functions like getSelection(), which are neither stable over time nor portable across browsers and languages 2.

    The example code could be modified in a number of ways for specific applications. For instance other mechanisms could be employed to select which DOM objects are initialized for charClick callbacks. Surrogate pairs could be supported in the i loop too.

      <!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 &#xE6;&#x20AC; &ndash; &#xFD7;&#xD8; &mdash; string.</p>
          <p id='p1'>Next                                                                     
    0 讨论(0)
  • 2020-12-09 10:33
    $('div').click( function () {
      getSelectionPosition (); 
    });
    
    
    function getSelectionPosition () {
      var selection = window.getSelection();
      console.log(selection.focusNode.data[selection.focusOffset]);
      alert(selection.focusOffset);
    }
    

    This works with "click", as well as with a "range" for most browsers. (selection.type = "caret" / selection.type = "range").

    selection.focusOffset() gives you the position in the inner node. If elements are nested, within <b> or <span> tags for example, it will give you the position inside the inner element, not the full text, more or less. I'm unable to "select" the first letter of a sub tag with focusOffset and "caret" type (click, not range select). When you click on the first letter, it gives the position of the last element before the start of tag plus 1. When you click on the second letter, it correctly gives you "1". But I didn't find a way to access the first element (offset 0) of the sub element. This "selection/range" stuff seems buggy (or very non-intuitive to me). ^^

    But it's quite simple to use without nested elements! (Works fine with your <div>)

    Here is a fiddle

    Important edit 2015-01-18:

    This answer worked back when it was accepted, but not anymore, for reasons given below. Other answers are now most useful.

    • Matthew's general answer
    • The working example provided by Douglas Daseeco.

    Both Firefox and Chrome debugged window.getSelection() behavior. Sadly, it is now useless for this use case. (Reading documentation, IE 9 and beyond shall behave the same).

    Now, the middle of a character is used to decide the offset. That means that clicking on a character can give back 2 results. 0 or 1 for the first character, 1 or 2 for second, etc.

    I updated the JSFiddle example.

    Please note that if you resize the window (Ctrl + mouse), the behavior is quite buggy on Chrome for some clicks.

    0 讨论(0)
  • 2020-12-09 10:43

    You could, using JavaScript, break each character into it's own SPAN tag and add an onclick event for each. Then, read the x, y position from the event data when the SPAN is clicked.

    As well, you will have access to the character clicked with event.target.innerHTML

    0 讨论(0)
  • 2020-12-09 10:47

    In many cases, a possible solution can be to add zero-width space character (U+200B) between each char of the content of the tag. Then using javascript window.getSelection().focusOffset + some simple computations does the job.

    Sample html code (including zero-width space characters):

    <div onclick='magic(this)'>T​h​i​s​ ​i​s​ ​a​ ​s​i​m​p​l​e​ ​e​x​a​m​p​l​e​.</div>
    

    Sample javascript code:

    <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>
    

    Seems to work widely, even on internet explorer!

    jsFidle: http://jsfiddle.net/by1a9pfm/

    0 讨论(0)
提交回复
热议问题