Spec-Zone.ru › Web APIs

Метод: caretPositionFromPoint()

Ограниченная доступность

Эта функция не соответствует Baseline, так как она не работает во всех широко используемых браузерах.

  • Подробнее
  • Полная совместимость
  • Отправить отзыв

Метод caretPositionFromPoint() интерфейса Document возвращает объект CaretPosition, содержащий узел DOM, а также позицию курсора и его смещение в этом узле.

Синтаксис

caretPositionFromPoint(x, y)
caretPositionFromPoint(x, y, options)

Параметры

x

Горизонтальная координата точки.

y

Вертикальная координата точки.

options Необязательный

Можно также указать следующие необязательные свойства.

shadowRoots Необязательный

Массив объектов ShadowRoot. Метод может возвратить позицию курсора для узла, определённого внутри теневого DOM указанного теневого корня. Если позиция курсора находится в теневом корне, который не был передан, возвращаемый CaretPosition будет переназначен на узел, являющийся хостом теневого корня.

Возвращаемое значение

Объект CaretPosition или null.

Возвращаемое значение null в случае отсутствия области просмотра (viewport) у документа, если x или y отрицательны или выходят за пределы области просмотра, или если координаты указывают на точку, в которой невозможно вставить маркер вставки текста.

Примеры

Разделение узлов текста в позиции курсора в DOM

Этот пример демонстрирует, как получить позицию курсора из выбранного узла DOM, использовать эту позицию для разделения узла и вставить разрыв строки между двумя узлами. Пример использует caretPositionFromPoint() для получения позиции курсора, если она поддерживается, с нестандартным методом Document.caretRangeFromPoint() в качестве резервного варианта.

Обратите внимание, что некоторые части кода скрыты, включая код, используемый для регистрации, так как он не нужен для понимания этого метода.

HTML

HTML определяет абзац текста.

<p>
  Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy
  eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam
  voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita
  kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
</p>

JavaScript

Метод ниже сначала проверяет поддержку document.caretPositionFromPoint и использует его для получения узла текста и смещения в позиции курсора. Если браузер не поддерживает этот метод, код проверяет поддержку document.caretRangeFromPoint и использует её вместо этого.

Если узел в позиции курсора — это узел текста, код затем разделяет узел на два в указанном смещении и вставляет разрыв строки между двумя узлами.

function insertBreakAtPoint(e) {
  let range;
  let textNode;
  let offset;

  if (document.caretPositionFromPoint) {
    range = document.caretPositionFromPoint(e.clientX, e.clientY);
    textNode = range.offsetNode;
    offset = range.offset;
  } else if (document.caretRangeFromPoint) {
    // Use WebKit-proprietary fallback method
    range = document.caretRangeFromPoint(e.clientX, e.clientY);
    textNode = range.startContainer;
    offset = range.startOffset;
  } else {
    // Neither method is supported, do nothing
    return;
  }

  // Logging code (uses hidden method to get substring with ^ at offset)
  if (textNode?.nodeType === 3) {
    const caretInText = getSubstringAroundOffset(textNode.textContent, offset);
    log(
      `node: ${textNode.nodeName}, offset: ${offset}, insert: ${caretInText}`,
    );
  }

  // Only split TEXT_NODEs
  if (textNode?.nodeType === 3) {
    let replacement = textNode.splitText(offset);
    let br = document.createElement("br");
    textNode.parentNode.insertBefore(br, replacement);
  }
}

Метод добавляется как обработчик события клика для любых элементов абзаца.

const paragraphs = document.getElementsByTagName("p");
for (const paragraph of paragraphs) {
  paragraph.addEventListener("click", insertBreakAtPoint, false);
}

Результаты

Нажмите где угодно в абзаце Lorem ipsum ... ниже, чтобы вставить разрыв строки в точке щелчка. Обратите внимание, что регистрация отображает nodeName, смещение и фрагмент выделенного узла с символом ^ в смещении.

Разделение узлов текста в позициях курсора в теневом DOM

Этот пример демонстрирует, как получить позицию курсора из выбранного узла внутри теневого корня. Пример очень похож на пример только для DOM, за исключением того, что часть текста находится внутри теневого корня. Мы предоставили кнопку, чтобы вы могли увидеть разницу, когда теневой корень передаётся/не передаётся в caretPositionFromPoint().

Обратите внимание, что некоторые части кода скрыты, включая код, используемый для регистрации, так как он не нужен для понимания этого метода.

HTML

HTML определяет абзац текста внутри элемента <div>. Абзац содержит элемент <span> с атрибутом id "host", который мы будем использовать в качестве хоста для теневого корня. Также есть некоторые кнопки, которые мы будем использовать для сброса примера и для добавления/удаления аргумента теневого корня в caretPositionFromPoint().

<button id="reset" type="button">Reset</button>
<button id="shadowButton" type="button">Add Shadow</button>
<div>
  <p>
    Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy
    eirmod tempor invidunt ut <span id="host"></span> labore et dolore magna
    aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo
    dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est
    Lorem ipsum dolor sit amet.
  </p>
</div>

CSS

Здесь мы используем CSS, чтобы сделать элемент #host красным и жирным. Это облегчает различение текста в DOM и текста в теневом DOM.

#host {
  color: red;
  font-weight: bold;
}

JavaScript

Сначала у нас есть код для заполнения нашего теневого DOM. Мы используем JavaScript для динамического присоединения теневого корня, потому что система примеров MDN не позволяет сделать это декларативно с помощью элемента <template>. Содержимое теневого DOM — это элемент <span>, содержащий текст "Я в теневом DOM".

const host = document.querySelector("#host");
const shadow = host.attachShadow({ mode: "open" });
const shadowSpan = document.createElement("span");
shadowSpan.textContent = "I'm in the shadow DOM";
shadow.appendChild(shadowSpan);

Далее мы добавляем обработчик для нашей кнопки "Включить/Отключить тень". Этот код переключает значение переменной useShadows и обновляет текст кнопки соответствующим образом.

let useShadows = false;

const shadowButton = document.querySelector("#shadowButton");
shadowButton.addEventListener("click", () => {
  useShadows = !useShadows;
  shadowButton.innerText = useShadows ? "Remove Shadow" : "Add Shadow";
});

Метод ниже сначала проверяет поддержку document.caretPositionFromPoint и использует его для получения узла текста и смещения в позиции курсора. Значение переменной useShadows используется для определения того, передаётся ли теневой корень, размещённый в нашем тексте, в caretPositionFromPoint().

  • Если браузер не поддерживает этот метод, код затем проверяет поддержку document.caretRangeFromPoint и использует её вместо этого.
  • Если узел в позиции курсора — это узел текста, код затем разделяет узел в указанном смещении и вставляет разрыв строки между ними.
  • Если узел — это элементный узел, то код вставляет элемент разрыва строки в узле в смещении.
function insertBreakAtPoint(e) {
  let range;
  let textNode;
  let offset;

  if (document.caretPositionFromPoint) {
    range = document.caretPositionFromPoint(
      e.clientX,
      e.clientY,
      useShadows ? { shadowRoots: [shadow] } : null,
    );
    textNode = range.offsetNode;
    offset = range.offset;
  } else if (document.caretRangeFromPoint) {
    // Use WebKit-proprietary fallback method
    range = document.caretRangeFromPoint(e.clientX, e.clientY);
    textNode = range.startContainer;
    offset = range.startOffset;
  } else {
    // Neither method is supported, do nothing
    return;
  }

  // Logging code (uses hidden method to get substring with ^ at offset)
  if (textNode) {
    if (textNode.nodeType === 3) {
      const caretInText = getSubstringAroundOffset(
        textNode.textContent,
        offset,
      );
      log(
        `type: TEXT_NODE, name: ${textNode.nodeName}, offset: ${offset}:
${caretInText}`,
      );
    } else if (textNode.nodeType === 1) {
      log(`type: ELEMENT_NODE, name: ${textNode.nodeName}, offset: ${offset}`);
    } else {
      log(
        `type: ${textNode.nodeType}, name: ${textNode.nodeName}, offset: ${offset}`,
      );
    }
  }

  // Insert line at caret
  if (textNode?.nodeType === 3) {
    // TEXT_NODE - split text at offset and add br
    let replacement = textNode.splitText(offset);
    let br = document.createElement("br");
    textNode.parentNode.insertBefore(br, replacement);
  } else if (textNode?.nodeType === 1) {
    // ELEMENT_NODE - Add br node at offset node
    let br = document.createElement("br");
    const targetNode = textNode.childNodes[offset];
    textNode.insertBefore(br, targetNode);
  } else {
    // Do nothing
  }
}

Наконец, мы добавляем два обработчика событий клика для элементов абзаца в DOM и в теневом корне соответственно. Обратите внимание, что нам нужно явно запросить элементы внутри shadowRoot , так как они не видны обычным методам запроса DOM.

// Click event handler <p> elements in the DOM
const paragraphs = document.getElementsByTagName("p");
for (const paragraph of paragraphs) {
  paragraph.addEventListener("click", insertBreakAtPoint, false);
}

// Click event handler <p> elements in the Shadow DOM
const shadowParagraphs = host.shadowRoot.querySelectorAll("p");
for (const paragraph of shadowParagraphs) {
  console.log(paragraph);
  paragraph.addEventListener("click", insertBreakAtPoint, false);
}

Результаты

Нажмите в абзаце Lorem ipsum ... до или после текста теневого DOM, чтобы вставить разрыв строки в точке щелчка. Обратите внимание, что в этом случае регистрация показывает выбранный TEXT_NODE, смещение и фрагмент выделенного узла с символом ^ в смещении.

Изначально теневой корень не передаётся в caretPositionFromPoint(), поэтому, если вы нажмёте на текст "Я в теневом DOM", возвращаемый узел позиции курсора — это родительский узел хоста в смещении теневого корня. Таким образом, разрыв строки добавляется перед узлом, а не в выбранной точке. Обратите внимание, что узел позиции курсора в этом случае имеет тип ELEMENT_NODE.

Если вы нажмёте кнопку "Добавить тень", теневой корень передаётся в caretPositionFromPoint(), поэтому возвращаемая позиция курсора — это конкретный выделенный узел внутри теневого DOM. Это заставляет текст теневого DOM вести себя как другой текст абзаца.

Спецификации

Спецификация
Модуль CSSOM View
# dom-document-caretpositionfrompoint

Совместимость с браузерами

Рабочие столы Мобильные устройства
Chrome Edge Firefox Opera Safari Chrome Android Firefox for Android Opera Android Safari на IOS Samsung Internet WebView Android
caretPositionFromPoint 128 128 20 114 Нет 128 20 85 Нет Нет 128
options_parameter 128 128 превью 131–133 114 Нет 128 131–133 85 Нет Нет 128

См. также

  • CaretPosition

© 2005–2024 MDN contributors.
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.
https://developer.mozilla.org/en-US/docs/Web/API/Document/caretPositionFromPoint

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API