从(换行符:正常)HTML 中获取特定行

3
我想知道是否可以使用JavaScript来提取以下页面的第三行内容:

<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>

我认为我的HTML代码如下:

enter image description here

红色下划线的那一行是第三行,会在视图中动态调整。

我尝试使用 .innerHTML.innerText 方法,但无法识别换行符。

我想如果能够获取每行的 scrollHeight,然后使用 JavaScript,但我在互联网上没有找到任何支持的方法。有什么想法吗?

注意:可以假设他/她可以访问 p 元素。我们可以使用客户端JS / HTML解决方案。


1
你可以对每个单词使用<span></span>,然后使用一个循环来确定何时每个单词的Y坐标发生更改。这只是一个想法。 - GetSet
整个操作可能会占用UI线程,是的。根据约定文本的长度而定。但作为一个概念,它应该能够以某种形式进行“异步化”。 - GetSet
@GetSet:你的想法很有帮助。你可以添加一个答案。 - vrintle
嗯,作为一个概念,我受限于不知道<p></p>元素是如何创建的。如果它是在服务器端创建的,那么如果服务器处理所有<span></span>的业务,这就有意义了。然而,为了完全自由,即使不考虑<p></p>是如何生成的,我也可以编写代码,但最好使用jQuery来实现更简洁的代码。不过,我可以提供一个算法。 - GetSet
1
假设您选择了纯客户端解决方案。(1)使用“inner-text”保存到变量中。(2)通过“空格”拆分段落(变量)以获取“单词”。(3)创建一个隐藏的<p></p>元素,其容器尺寸和CSS样式与您真正的<p></p>元素相同。(4)将来自.split()数组的每个单词(用空格分隔)写入隐藏元素中,但用<span></span>包装。(5)编写循环,按顺序检查每个单词(每个“span”)的Y。当Y更改时,您就知道您在“新行”上。 - GetSet
显示剩余7条评论
1个回答

2
我们可以做以下事情:
  • 通过空格字符将段落文本分割为所有单词
  • 将段落文本设置为空字符串
  • 追加每个单词并测量段落的内容大小 (请谨慎使用此方法,这样测量会导致大量布局重新计算)
  • 当段落的内容大小与先前的内容大小不同时,我们知道发生了换行
  • 当我们在第n行时,添加追加的单词直到达到新行
  • 该变量是提取的字符串
这个解决方案即使文本非常长也不会阻塞UI事件。为了实现这一点,我们可以将长时间运行的任务分成更小的部分,以便仍然可以处理UI事件。要拆分它,我们可以使用setTimeout(..., 0)。以这种方式使用setTimeout会推迟较短时间的任务。只有当它们处于消息队列的最前面时才会运行。只有当一个较短时间的任务完成后,下一个较短时间的任务才会被推迟到消息队列的末尾。这样就允许其他与UI相关的消息(例如单击事件监听器的回调函数)也能运行;从而实现非阻塞。

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>


杰出的解决方案 - GetSet

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接