Мы можем сделать следующее:
- Разделить текст абзаца на символ
space
, чтобы получить все слова - Установить для текста абзаца пустую строку
- Добавьте каждое слово и измерьте размер содержимого абзаца (используйте это экономно, измерение таким способом вызывает много пересчета макета)
- Когда размер содержимого абзаца не совпадает с предыдущим размером контента, мы знаем, что произошел разрыв строки
- Когда мы находимся на n-й строке, добавляем добавленные слова, пока не будет достигнута новая строка
- Сказал переменная - извлеченная строка
Это решение не блокирует события пользовательского интерфейса, даже если текст очень длинный. Чтобы добиться этого в этом решении, мы можем разделить долгосрочную задачу на более мелкие , чтобы события пользовательского интерфейса все еще могли обрабатываться. Чтобы разделить его, мы можем использовать setTimeout(..., 0)
. Использование setTimeout
таким способом откладывает выполнение более коротких задач. Они запускаются, только если они являются самыми передними из очереди сообщений . Только после выполнения более короткой задачи следующая более короткая задача будет отложена до конца очереди сообщений. Это позволяет также запускать другие сообщения, связанные с пользовательским интерфейсом (например, функцию обратного вызова для прослушивателя событий щелчка); таким образом, неблокирующий.
const p = document.querySelector('p')
const texts = p.innerText.split(' ')
const textsLength = texts.length
const nthLine = 3 // The line from which you extract the string
let i = 0
let currentWord = 0
let currentLine = 0
let currentBoxHeight = 0
let nthLineText = ''
p.innerText = ''
function getNthLineText() {
// Split the long-running tasks of measuring words to only 100 word per callback function
for (currentWord; currentWord < (i + 1) * 100 && currentWord < textsLength; currentWord++) {
p.innerText += ` ${texts[currentWord]}`
// Paragraph box is larger? Line-break occurred
if (p.scrollHeight > currentBoxHeight) {
currentBoxHeight = p.scrollHeight
currentLine += 1
}
// We're at the nth line we want to extract, add the appended word to the result variable
if (currentLine === nthLine) {
nthLineText += ` ${texts[currentWord]}`
}
}
if (currentLine > nthLine || currentWord >= textsLength) {
console.log(`String extracted: ${nthLineText === '' ? 'None extracted' : nthLineText}`)
p.innerText = texts.join(' ')
} else {
setTimeout(getNthLineText, 0)
}
}
getNthLineText()
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum felis elit, scelerisque id rhoncus et, hendrerit nec turpis. Phasellus eget condimentum justo. Aliquam porta, risus sed elementum hendrerit, turpis urna posuere libero, eget facilisis sem purus sed mi. Nulla pulvinar nibh quis bibendum lacinia. Aenean eu nibh pharetra, imperdiet mi eget, vehicula mauris. In hac habitasse platea dictumst. Phasellus ante enim, bibendum quis turpis a, volutpat auctor mi. Mauris scelerisque sem a ornare dignissim. Nullam in sem ac turpis aliquet dictum sit amet dignissim est.</p>