Получить все элементы блока DOM для выбранных текстов
При выборе текстов в документах HTML можно начинать с одного элемента DOM другому элементу, возможно, проходя через несколько других элементов на этом пути. Используя DOM API, можно получить диапазон выбора, выбранных текстов и даже родительский элемент всех выбранных элементов DOM (используя commonAncestorContainer или parentElement() на основе используемого браузера). Тем не менее, я не знаю, что может указать все элементы, содержащие элементы выбранных текстов, кроме получения единственного родительского элемента, который содержит их все. Использование родительского элемента и перемещение дочерних узлов не сделают этого, так как могут быть другие братья и сестры, которые не выбраны внутри этого родителя.
Итак, есть ли способ, чтобы я мог получить все эти элементы, содержащие выбранные тексты. Я в основном заинтересован в получении элементов блока (p, h1, h2, h3,... и т.д.), Но я считаю, что если есть способ получить все элементы, тогда я могу пройти через них и отфильтровать их, чтобы получить то, что я хотеть. Я приветствую любые идеи и предложения.
Спасибо.
Ответы
Ответ 1
Ключ window.getSelection().getRangeAt(0)
https://developer.mozilla.org/en/DOM/range
Вот пример кода, с которым вы можете играть, чтобы делать то, что хотите. Упоминание того, что вы действительно хотите, чтобы это под вопросом, поможет людям предоставить лучшие ответы.
var selection = window.getSelection();
var range = selection.getRangeAt(0);
var allWithinRangeParent = range.commonAncestorContainer.getElementsByTagName("*");
var allSelected = [];
for (var i=0, el; el = allWithinRangeParent[i]; i++) {
// The second parameter says to include the element
// even if it not fully selected
if (selection.containsNode(el, true) ) {
allSelected.push(el);
}
}
console.log('All selected =', allSelected);
Это не самый эффективный способ, вы можете пересечь DOM самостоятельно с помощью Range startContainer/endContainer, а также nextSibling/previousSibling и childNodes.
Ответ 2
Вы можете использовать мою Rangy library для этого. Он обеспечивает реализацию объектов DOM Range и Selection для всех браузеров, включая IE, и имеет дополнительные методы Range. Один из них getNodes()
:
function isBlockElement(el) {
// You may want to add a more complete list of block level element
// names on the next line
return /h[1-6]|div|p/i.test(el.tagName);
}
var sel = rangy.getSelection();
if (sel.rangeCount) {
var range = sel.getRangeAt(0);
var blockElements = range.getNodes([1], isBlockElement);
console.log(blockElements);
}
Ответ 3
Похоже, вы могли бы использовать Переход от jQuery API.
Возможно .contents()
Надеюсь, что это поможет!
Ответ 4
Вот подход es6, основанный на ответе @Juan Mendes:
const selection = window.getSelection();
const range = selection.getRangeAt(0);
const elementsFromAncestorSelections = range.commonAncestorContainer.getElementsByTagName("*");
const allSelectedElements = Array.from(elementsFromAncestorSelections).reduce(
(elements, element) =>
selection.containsNode(element, true)
? [...elements, element]
: elements,
[],
);