AbstractRange
Базовая Широко доступная
Эта функция хорошо зарекомендовала себя и работает на многих устройствах и версиях браузеров. Она доступна в браузерах с марта 2017 года.
Абстрактный интерфейс AbstractRange является базовым классом, на котором определены все типы диапазонов DOM. Диапазон — это объект, указывающий начальную и конечную точки раздела содержимого в документе.
Примечание: В качестве абстрактного интерфейса вы не сможете напрямую создать объект типа AbstractRange. Вместо этого используйте интерфейсы Range или StaticRange. Чтобы понять разницу между этими двумя интерфейсами и как выбрать подходящий для ваших нужд, обратитесь к документации каждого интерфейса.
Свойства экземпляра
-
collapsedТолько для чтения -
Булево значение, которое является
true, если диапазон сжат. Сжатый диапазон — это диапазон, у которого начальная и конечная позиции совпадают, что приводит к диапазону длиной ноль символов. -
endContainerТолько для чтения -
Объект
Node, в котором расположена конечная точка диапазона, как указано свойствомendOffset. -
endOffsetТолько для чтения -
Целочисленное значение, указывающее смещение в символах от начала содержимого узла до последнего символа диапазона, представленного объектом диапазона. Это значение должно быть меньше длины узла
endContainer. -
startContainerТолько для чтения -
Объект DOM
Node, в котором расположена начальная точка диапазона, как указано свойствомstartOffset. -
startOffsetТолько для чтения -
Целочисленное значение, указывающее смещение в символах от начала содержимого узла до первого символа содержимого, на которое ссылается объект диапазона. Это значение должно быть меньше длины узла, указанного в
startContainer.
Методы экземпляра
Интерфейс AbstractRange не предоставляет никаких методов.
Примечания по использованию
Типы диапазонов
Все диапазоны содержимого в document описываются с помощью экземпляров интерфейсов, основанных на AbstractRange. Существует два таких интерфейса:
Range-
Интерфейс
Rangeсуществует уже давно и был переопределен только недавно, чтобы базироваться наAbstractRange, поскольку возникла необходимость определить другие формы данных диапазонов.Rangeпредоставляет методы, позволяющие изменять конечные точки диапазона, а также методы сравнения диапазонов, обнаружения пересечений между диапазонами и т. д. StaticRange-
StaticRange— это базовый диапазон, который нельзя изменить после его создания. То есть, когда изменяется дерево узлов, диапазон не меняется. Это полезно, когда вам нужен диапазон, который будет использоваться только один раз, поскольку он избегает производительности и ресурсных затрат более сложного интерфейсаRange.
Содержимое элементов
При попытке получить доступ к содержимому элемента помните, что сам элемент является узлом, но и текст внутри него тоже. Чтобы установить конечную точку диапазона внутри текста элемента, найдите текстовый узел внутри элемента:
const startElem = document.querySelector("p");
const endElem = startElem.querySelector("span");
const range = document.createRange();
range.setStart(startElem, 0);
range.setEnd(endElem, endElem.childNodes[0].length / 2);
const contents = range.cloneContents();
document.body.appendChild(contents);
В этом примере создается новый диапазон, range, и его начальная точка устанавливается на третий дочерний узел первого элемента. Конечная точка устанавливается посередине первого дочернего элемента span, а затем диапазон используется для копирования содержимого диапазона.
Диапазоны и иерархия DOM
Чтобы определить диапазон символов в документе, который может охватывать ноль или более границ узлов и который максимально устойчив к изменениям DOM, вы не можете указать смещение к первому и последнему символам в HTML. Для этого есть несколько причин.
Во-первых, после загрузки страницы браузер не думает в терминах HTML. После загрузки страница представляет собой дерево объектов DOM Node, поэтому вам нужно указать начальную и конечную точки диапазона в терминах узлов и позиций внутри узлов.
Во-вторых, для максимальной поддержки изменяемости дерева DOM вам нужен способ представления позиций, относящихся к узлам в дереве, а не глобальных позиций во всем документе. Определяя точки внутри документа как смещения внутри данного узла, эти позиции остаются согласованными с содержимым даже при добавлении, удалении или перемещении узлов внутри дерева DOM — в разумных пределах. Существуют довольно очевидные ограничения (например, если узел перемещается за конечную точку диапазона или содержимое узла сильно изменяется), но это намного лучше, чем ничего.
В-третьих, использование позиций, относительных к узлам, для определения начальной и конечной точек обычно будет проще сделать производительным. Вместо того, чтобы браузеру приходилось обрабатывать весь DOM, пытаясь понять, к чему относится ваше глобальное смещение, он может напрямую обратиться к узлу, указанному начальной точкой, и начать оттуда, двигаясь вперед, пока не достигнет заданного смещения в конечном узле.
Для иллюстрации рассмотрим HTML ниже:
<div class="container">
<div class="header">
<img src="" class="sitelogo" />
<h1>The Ultimate Website</h1>
</div>
<article>
<section class="entry" id="entry1">
<h2>Section 1: An interesting thing…</h2>
<p>A <em>very</em> interesting thing happened on the way to the forum…</p>
<aside class="callout">
<h2>Aside</h2>
<p>An interesting aside to share with you…</p>
</aside>
</section>
</article>
<pre id="log"></pre>
</div>
После загрузки HTML и построения представления DOM документа, полученное дерево DOM выглядит так:
На этой диаграмме узлы, представляющие HTML-элементы, показаны зеленым цветом. Каждая строка под ними показывает следующий уровень глубины в дереве DOM. Синие узлы — это текстовые узлы, содержащие текст, который отображается на экране. Содержимое каждого элемента связано с ним в дереве, потенциально порождая ряд ветвей ниже, поскольку элементы включают другие элементы и текстовые узлы.
Если вы хотите создать диапазон, включающий содержимое элемента <p>, содержимое которого "A <em>very</em> interesting thing happened on the way to the forum…", вы можете сделать это так:
const pRange = document.createRange();
pRange.selectNodeContents(document.querySelector("#entry1 p"));
Поскольку мы хотим выбрать всё содержимое элемента <p>, включая его потомков, это работает идеально.
Если мы хотим вместо этого скопировать текст "An interesting thing…" из заголовка элемента <section> (элемента h2) до конца букв "ve" в элементе <em> в абзаце ниже него, следующий код сработает:
const range = document.createRange();
const startNode = document.querySelector("section h2").childNodes[0];
range.setStart(startNode, 11);
const endNode = document.querySelector("#entry1 p em").childNodes[0];
range.setEnd(endNode, 2);
const fragment = range.cloneContents();
Здесь возникает интересная проблема — мы собираем содержимое из нескольких узлов, расположенных на разных уровнях иерархии DOM, и только часть одного из них. Как должен выглядеть результат?
Как оказалось, спецификация DOM благополучно решает эту проблему. Например, в этом случае мы вызываем cloneContents() в диапазоне для создания нового объекта DocumentFragment, предоставляющего поддерево DOM, которое дублирует содержимое указанного диапазона. Для этого cloneContents() строит все необходимые узлы для сохранения структуры указанного диапазона, но не больше, чем необходимо.
В этом примере начальная точка указанного диапазона находится внутри текстового узла под заголовком раздела, что означает, что новый DocumentFragment должен содержать h2 и, ниже него, текстовый узел.
Конечная точка диапазона расположена под элементом <p>, поэтому он будет нужен в новом фрагменте. Также потребуется текстовый узел, содержащий слово "A", поскольку оно включено в диапазон. Наконец, будет добавлен элемент <em> и текстовый узел под ним под <p>.
Содержимое текстовых узлов определяется смещениями в эти текстовые узлы при вызове setStart() и setEnd(). Учитывая смещение 11 в текст заголовка, этот узел будет содержать "An interesting thing…". Аналогично, последний текстовый узел будет содержать "ve", учитывая запрос на первые два символа конечного узла.
Полученный фрагмент документа выглядит так:
Обратите особое внимание на то, что содержимое этого фрагмента находится под общим родительским узлом самых верхних узлов в нем. Родительский узел <section> не нужен для копирования содержимого, поэтому он не включен.
Пример
Рассмотрим этот простой фрагмент HTML.
<p><strong>This</strong> is a paragraph.</p>
Представьте, что вы используете Range для извлечения слова «абзац» из этого фрагмента. Код для этого выглядит следующим образом:
const paraNode = document.querySelector("p");
const paraTextNode = paraNode.childNodes[1];
const range = document.createRange();
range.setStart(paraTextNode, 6);
range.setEnd(paraTextNode, paraTextNode.length - 1);
const fragment = range.cloneContents();
document.body.appendChild(fragment);
Сначала мы получаем ссылки на сам узел абзаца, а также на второй дочерний узел внутри абзаца. Первый дочерний узел — это элемент <strong>. Второй дочерний узел — это текстовый узел «является абзацем».
Получив ссылку на текстовый узел, мы создаём новый объект Range, вызвав createRange() для самого Document. Мы устанавливаем начальную позицию диапазона на шестой символ строки текстового узла и конечную позицию на длину строки текстового узла минус один. Это устанавливает диапазон, охватывающий слово «абзац».
Затем мы завершаем процесс, вызвав cloneContents() для Range, чтобы создать новый объект DocumentFragment, содержащий часть документа, охватываемую диапазоном. После этого мы используем appendChild() для добавления этого фрагмента в конец тела документа, полученного из document.body.
Результат выглядит так:
Спецификации
| Спецификация |
|---|
| DOM # interface-abstractrange |
Совместимость с браузерами
| Рабочие столы | Мобильные устройства | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
| Chrome | Edge | Firefox | Opera | Safari | Chrome Android | Firefox для Android | Opera Android | Safari на iOS | Samsung Internet | WebView Android | |
AbstractRange |
90 | 9018–79 | 69 | 76 | 14.1 | 90 | 79 | 64 | 14.5 | 15.0 | 90 |
collapsed |
90 | 9018–79 | 69 | 76 | 14.1 | 90 | 79 | 64 | 14.5 | 15.0 | 90 |
endContainer |
90 | 9018–79 | 69 | 76 | 14.1 | 90 | 79 | 64 | 14.5 | 15.0 | 90 |
endOffset |
90 | 9018–79 | 69 | 76 | 14.1 | 90 | 79 | 64 | 14.5 | 15.0 | 90 |
startContainer |
90 | 9018–79 | 69 | 76 | 14.1 | 90 | 79 | 64 | 14.5 | 15.0 | 90 |
startOffset |
90 | 9018–79 | 69 | 76 | 14.1 | 90 | 79 | 64 | 14.5 | 15.0 | 90 |
© 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/AbstractRange