Диапазон — это встроенный объект JavaScript. Вообще говоря, он не используется во многих местах. В основном он используется в некоторых интерактивных сценах, таких как выделение аннотаций. Лучше сказать, что он не используется. , поэтому я подытожу здесь заметки, не вдаваясь слишком глубоко.
Следует отметить, что многие из методов здесь являются экспериментальными функциями, поэтому использование производственной среды должно быть осторожным.Подробности см. в MDN. Я не буду здесь вдаваться в подробности.
Сценарии применения ассортимента
Таких относительно необычных API-приложений не так много, здесь мы сначала разбираемся со сценариями применения диапазона.
-
Это обычная электронная книга и так далее.
-
Базовая документация, необходимая для машинного обучения маркировки человеком (что я сделал)
Конечно, должно быть много других сценариев, и я с ними особо не контактировал, кому интересно, они могут узнать о них сами.
что такое диапазон
Как следует из названия, Range на самом деле можно рассматривать как выделенный текстовый диапазон, но Range не зависит от выбора мыши, и мы можем создать или клонировать его самостоятельно. Но прежде чем мы подробно поговорим о Range, давайте взглянем на Selection.
Как показано на рисунке, когда мы выделяем фрагмент текста, мы можем передатьwindow.getSelection
чтобы получить объект Selection
Выбор можетwindow.getSelection().toString()
Получить выделенный текст напрямую, но часто мы хотим получить не выделенный текст, а получить местоположение выделенного текста и сохранить его. Здесь в игру вступает Range.
window.getSelection().getRangeAt(0)
Объект Selection можно преобразовать в объект Range.
Нам нужно сосредоточиться на startContainer, endContainer, startOffset, endOffset. Эти четыре свойства могут найти выделенный текст.
Как показано на рисунке выше, мы знаем, что элементы Dom расположены в секциях, где контейнер ссылается на каждую секцию, а смещение — это выбранная позиция. Диапазон должен быть непрерывным, чтобы мы могли найти полный диапазон.
Хранение диапазона
Если он используется в качестве выделения, диапазон должен храниться на сервере, но в качестве js-объекта диапазон не может быть напрямую сохранен в базе данных, в это время диапазон должен быть обработан.
Как упоминалось выше, Range можно создать вручную:document.createRange
:
var range = document.createRange();
range.setStart(startNode, startOffset);
range.setEnd(endNode, endOffset);
здесьstartNode
Относится к startContainer, который, естественно, относится к элементу dom. Когда вы видите это, у вас должен быть план в голове. Единственное, что нелегко сохранить, — это элемент dom. Затем мы можем преобразовать элемент dom в селектор и сохраните его.Получите элемент dom с помощью селектора.
Конечно, у нас есть и другие варианты: xpath, в основном потому, что я использовал xpath, когда взялся за проект.Код для преобразования dom в xpath выглядит следующим образом:
// 获取一个元素的xpath
function getElementXPath (element) {
if (!element) return null
if (element.id) {
return `//*[@id=${element.id}]`
} else if (element.tagName === 'BODY') {
return '/html/body'
} else {
const sameTagSiblings = Array.from(element.parentNode.childNodes)
.filter(e => e.nodeName === element.nodeName)
const idx = sameTagSiblings.indexOf(element)
return getElementXPath(element.parentNode) +
'/' +
element.tagName.toLowerCase() +
(sameTagSiblings.length > 1 ? `[${idx + 1}]` : '')
}
}
Преобразовать xpath в диапазон:
function createRangeFromXPathRange (xpathRange) {
var startContainer,
endContainer,
endOffset,
evaluator = new XPathEvaluator()
// must have legal start and end container nodes
startContainer = evaluator.evaluate(
xpathRange.startContainerPath,
document.documentElement,
null,
XPathResult.FIRST_ORDERED_NODE_TYPE,
null
)
if (!startContainer.singleNodeValue) {
return null
}
if (xpathRange.collapsed || !xpathRange.endContainerPath) {
endContainer = startContainer
endOffset = xpathRange.startOffset
} else {
endContainer = evaluator.evaluate(
xpathRange.endContainerPath,
document.documentElement,
null,
XPathResult.FIRST_ORDERED_NODE_TYPE,
null
)
if (!endContainer.singleNodeValue) {
return null
}
endOffset = xpathRange.endOffset
}
// map to range object
var range = document.createRange()
range.setStart(startContainer.singleNodeValue, xpathRange.startOffset)
range.setEnd(endContainer.singleNodeValue, endOffset)
return range
}
Суммировать
Примечания к этой статье не будут представлять слишком много API или слишком глубоко, но идеи использования определены. взаимное поощрение.