Подтвердить что ты не робот

Определить индекс позиции символа в HTML-элементе при нажатии

У меня есть элемент HTML, внутри которого есть только видимый текст. Этот пример представляет собой элемент <div>, но он может быть <span>, <p> или другим элементом DOM.

<div>This is a simple example.</div>

При щелчке я могу получить позицию курсора на поверхности div, но мне нужно определить положение ближайшего символа и/или его индекса в строку div.innerHTML во время щелчка.

Я нашел аналогичную реализацию в методе getCharNumAtPosition в объектах текста SVG здесь.

Возможно ли реализовать такую ​​функцию в JavaScript, которая работает с HTML?

(Решения были бы наиболее полезными, если бы они были переносимыми в большинстве современных браузеров, работали с большинством письменных языков и основывались на относительно стабильных стандартах, чтобы впоследствии они перестали работать.)

4b9b3361

Ответ 1

$('div').click( function () {
  getSelectionPosition (); 
});


function getSelectionPosition () {
  var selection = window.getSelection();
  console.log(selection.focusNode.data[selection.focusOffset]);
  alert(selection.focusOffset);
}

Это работает с "click", а также с "диапазоном" для большинства браузеров. (selection.type = "caret"/selection.type = "range").

selection.focusOffset() дает вам положение во внутреннем node. Если элементы вложены, например, в теги <b> или <span>, это даст вам положение внутри внутреннего элемента, а не полного текста, более или менее. Я не могу "выбрать" первую букву субэлемента с типом focusOffset и "caret" (щелчок, а не выбор диапазона). Когда вы нажимаете на первую букву, она дает позицию последнего элемента перед началом тега плюс 1. Когда вы нажимаете на вторую букву, она правильно дает вам "1". Но я не нашел способ получить доступ к первому элементу (смещение 0) вспомогательного элемента. Этот материал "выбор/диапазон" кажется багги (или очень неинтуитивным для меня). ^^

Но он довольно прост в использовании без вложенных элементов! (Отлично работает с вашим <div>)

Вот скрипка

Важное изменение 2015-01-18:

Этот ответ сработал, когда он был принят, но уже не по причинам, приведенным ниже. Другие ответы теперь наиболее полезны.

  • Общий ответ Мэтью
  • Рабочий пример, представленный Дугласом Дасеке.

Оба Firefox и Chrome отлаживают поведение window.getSelection(). К сожалению, теперь это бесполезно для этого случая использования. (Чтение документации, IE 9 и далее должно вести себя одинаково).

Теперь середина символа используется для определения смещения. Это означает, что нажатие на символ может вернуть 2 результата. 0 или 1 для первого символа, 1 или 2 для второго и т.д.

Я обновил пример JSFiddle.

Обратите внимание, что если вы измените размер окна (Ctrl + мышь), поведение довольно затруднительно для Chrome за несколько кликов.

Ответ 2

Вы можете, используя JavaScript, разбить каждый символ на свой собственный тег SPAN и добавить событие onclick для каждого. Затем прочитайте позицию x, y из данных события при щелчке по SPAN.

Кроме того, у вас будет доступ к символу, нажатому с помощью event.target.innerHTML

Ответ 3

Этот пример - быстрая загрузка блоков умеренного размера, портативных и надежных. Хотя его элегантность не сразу проявляется, надежность заключается в создании простой индивидуальной переписки между международными символами и прослушивателями событий DOM 1.

Лучше полагаться только на широко распространенные кодировки символов, DOM и ECMA, как в этом примере. Другие подходы часто полагаются на атрибуты или функции целевого события низкого уровня, такие как getSelection(), которые не являются ни стабильными с течением времени, ни переносимыми между браузерами и языками 2.

Примерный код может быть изменен несколькими способами для определенных приложений. Например, для выбора объектов DOM, инициализированных для обратных вызовов charClick, можно использовать другие механизмы. Суррогатные пары могут поддерживаться и в цикле 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 &#xE6;&#x20AC; &ndash; &#xFD7;&#xD8; &mdash; string.</p>
      <p id='p1'>Next 𐐷 😀E para.</p>
      <p id='p2'>&copy; 2017</p>
      <hr>
      <p id='result'>&nbsp;</p>
  </body>
  </html>

Прежде чем использовать это в интернационализированных сценариях производства, рекомендуется полное тестирование. Если обнаружены ошибки, предложите изменения или добавить комментарии, чтобы уточнения могли быть добавлены.


Примечания

[1] Эти прослушиватели событий могли быть добавлены напрямую, но потребовалось бы разветвление для браузера или дополнительный вес библиотек, которые не добавили бы особой скорости или удобства для этого варианта использования.

[2] См. примечания об избранных событиях в Страница событий W3C UI.

Ответ 4

Во многих случаях возможным решением может быть добавление символа пробела (U + 200B) нулевой ширины между каждым символом содержимого тега. Затем используйте javascript window.getSelection().focusOffset + некоторые простые вычисления выполняют эту работу.

Пример html-кода (включая пробелы в пробеле):

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

Пример кода 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>

Кажется, он работает широко, даже в Интернете исследователя!

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