Метод: 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 вести себя как другой текст абзаца.
Спецификации
Совместимость с браузерами
| Рабочие столы | Мобильные устройства | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
| 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 |
См. также
© 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