#javascript #html
#javascript #HTML
Вопрос:
Я хочу получить массив всех ссылок из абзаца innerHTML и сохранить их начальный и конечный индексы вместе с содержимым в сравнении с textContent.
<p id ="1">This is a <a href ="/hey">Link</a> and this is also a <a href="/hey">Link</a></p>
Итак, для этого я пытаюсь получить что-то вроде:
//I know this is formatted weird, just showing an example of what data would like at end.
links = [
'link1': { start_index: 11, end_index: 14, href: '/hey, text: 'Link'},
'link2': { start_index: 35, end_index: 38, href: '/hey, text: 'Link'},
]
Начальный индекс и конечный индекс должны основываться на расположении ссылок в текстовом контенте абзаца.
Я пытался использовать indexOf ()
str = document.getElementById("1").innerHTML;
var index_start = str.indexOf("<a href ="/hey">Link</a>");
Но это просто вернет индекс ссылки в innerHTML, я не уверен, как получить ее местоположение в textContent или как получить местоположение всех ссылок.
Спасибо и извините, если это сбивает с толку.
Комментарии:
1. Каков здесь вариант использования более высокого уровня? Подумайте, что могут быть другие встроенные элементы, содержащие текст, также подобный
<span>
или<strong>
. Если есть, что учитывается?2. Содержимое всегда будет иметь только hrefs и предназначено для отправки данных на серверную часть, где каждая ссылка расположена в открытом тексте, чтобы PHP мог затем манипулировать ими, используя начальный и конечный индексы.
3. Таким образом, вы говорите, что никогда не будет других встроенных элементов перед
<a>
? Все еще не очень понятно, для чего вам это нужно4. хм! Это становится сложнее, когда есть две ссылки в одном
p
5. @AlwaysHelping Это обязательно делает!!
Ответ №1:
Это было немного сложно сделать, но я, наконец, сделал это.
Следующий код сработал для меня, с вашим примером.
const str = document.getElementById('1')
const linksInStr = [...str.querySelectorAll('a')]
let strInnerHTML = str.innerHTML
const links = linksInStr.map((element) => {
const urlProps = new URL(element.href)
const el = `<a href="${urlProps.pathname}">${element.textContent}</a>`
const start_index = strInnerHTML.indexOf(el)
const end_index = start_index element.textContent.length
strInnerHTML = strInnerHTML.replace(el, element.textContent)
return { start_index, end_index, href: urlProps.pathname, text: element.textContent }
})
console.log(links)
<p id="1">This is a <a href="/hey">Link</a> and this is also a <a href="/hey2">Link2</a></p>
Пожалуйста, обратите внимание, что мне пришлось изменить href и textContent второго элемента «a», добавив «2», потому что метод «indexOf» возвращает индекс только первого текста, который соответствует запросу.
Комментарии:
1. Выглядит хорошо! Единственная проблема, которую я вижу, заключается в том, что если текст ссылки существует в другом месте текста абзаца, то получение indexOf может быть отключено.
2. Эй, я немного изменил код, чтобы избежать этой проблемы. Теперь он соответствует только точному элементу «a» innerHTML вместо его textContent, чтобы избежать проблемы с методом indexOf.
3. Я думаю, что это становится еще сложнее, используя длину html, чтобы собрать его обратно позже. Не пытаюсь выделить ваши ссылки отдельно, потому что это интересное упражнение и ясно видно, что вы приложили хорошие усилия к решению. Хорошая работа
4. @N-bred Wao. Очень хороший вариант. Я собирался применить похожее решение, но был чем-то занят!
Ответ №2:
Вот исходное концептуальное решение.
Он создает клон <p>
затем заменяет ссылки в этом клоне заполнителем ||
, который, в свою очередь, позволяет разбить текстовую строку на массив, используя этот заполнитель.
Затем он отображает ссылки в массив объектов и берет предыдущую длину текста из массива разделенного текста (пока не из начала абзаца, а из предыдущей ссылки).
При немного большей доработке должно быть довольно легко перепроектировать это, чтобы поместить ссылки обратно в текст
const p = document.querySelector('p');
const txtArray = getTextInArray(p)
const links = Array.from(p.querySelectorAll('a')).map((el, i) => {
return {
href: el.href,
linkTxt: el.textContent,
prevTxtLength: txtArray[i].length
}
})
console.log(links)
function getTextInArray(p) {
let clone = p.cloneNode(true);
clone.querySelectorAll('a').forEach(a => a.replaceWith('||'));
return clone.textContent.split('||');
}
<p>Some text <a href="foo">Foo</a> some more text <a href="boo">Boo</a></p>
Комментарии:
1. Так это в основном для скребка?
2. Очень простой текстовый редактор, который не позволяет использовать форматированный текст, кроме ссылок, а затем данные, хранящиеся в json, для чего-либо еще. Но не хотел затруднять пользователей вводом bbcode / wikitext / markdown, поэтому просто кнопка, которая добавляет ссылку на абзац в вашей позиции курсора.
3. Ну, может быть, моя идея о том, чтобы поместить текст в массив, также является способом его сохранения. Упрощает создание ссылки обратно, если она уже сохранена в array
4. Это хороший момент, о котором я не подумал. В основном я думал хранить обычный текст и ссылки отдельно. Один для отображения теста просто как текста или просто простого запроса ссылок в тексте. Не думал о том, чтобы разделить все это дело на части. Текст, ссылка, текст, ссылка. В этом есть большой смысл.
5. @charlietfl Отличный друг!