javascript - 在 chromium/puppeteer 中获取按列数拆分的 div 边界框

标签 javascript css puppeteer

当我有如下所示的列布局时,chrome 只会为两列生成一个边界框,边界框是它们不在列中时的高度。我想分别获取两列的边界框。

采用这样的布局:

.container{
  column-count: 2;
}
<div class="container">
  <h1>Hello</h1>
  <span>text text text texttext text text text text text text text text text text text text text text text text text text text text texttext texttext text text text text text text text text text text text text text text text text text text text text text text text text text text text text texttext text text texttext texttext text text text text text text text</p>
</span>

在两列中生成文本。这会将 span 分成两部分,一部分在左列,一部分在右列。我怎样才能得到只有左边部分的边界框,只有右边部分的边界框?那如果拆分成 3 列呢?

getBoundingClientRect() 只返回边界矩形,就好像它都在一列中一样。

最佳答案

您可以使用 DOMRange's getBoundingClientRect ,与 Element 不同的是,它能够直接获取渲染文本的 BBox。

基本思想是从元素的文本内容中选择每个字符,然后检查其 BBox 以手动组成列的 BBox。

检查新列何时出现的第一个想法是验证当前字符的顶部位置是否低于前一个,但是如果是单行元素(至少 Firefox 和 Safari 会生成),这将失败。
因此,为了避免这种情况,最好检查前一个字符的右侧和下一个字符的左侧之间的距离。它有时会大于 1,因此该解决方案也不是完美的,因为它需要使用一些经验值,但根据我能做的少数测试,它似乎仍然是最有效的解决方案。

function getRenderedColumns( node ) {
  // we only deal with TextNodes
  if( !node || !node.parentNode || node.nodeType !== 3 ) {
    return [];
  }
  // our Range object form which we'll get the characters positions
  const range = document.createRange();
  // here we'll store all our columns
  const columns = [];
  // begin at the first character
  range.setStart( node, 0 );

  let str = node.textContent;
  let { top, right, bottom, left } = range.getBoundingClientRect();
  let lastRight = right;
  
  let current = 1; // we already have the first chars's rect

  // iterate over all characters
  while( current <= str.length ) {
    // move our cursor
    range.setStart( node, current );
    if( current < str.length - 1 ) {
      range.setEnd( node, current + 1 ); // wrap it (for Chrome...)
    }
    // get the BBox of this character
    const rect = range.getBoundingClientRect();
    // if we moved by more than 10px on x
    const new_column = rect.left - lastRight > 10;
    lastRight = rect.right;
    if( new_column ) {
      columns.push( {
        top,
        left,
        width: right - left,
        height: bottom - top
      } );
      top = rect.top;
      right = rect.right;
      bottom = rect.bottom;  
      left = rect.left;
    }
    else { // extend our column's rect
      bottom = Math.max( bottom, rect.bottom );
      right = Math.max( right, rect.right );
    }
    current++;
  }
  // push the last column
  columns.push( {
    top,
    left,
    width: right - left,
    height: bottom - top
  } );

  return columns;
}

function test( selector, color ) {
  const target = document.querySelector( selector );
  // note we use the TextNode as input
  const rects = getRenderedColumns( target.childNodes[0] ); 
  console.log( selector );
  console.log( rects );
  // make a visible marker for these rects
  rects.forEach(  rect => {
    const marker = document.createElement( 'div' );
    marker.classList.add( 'position-marker' );
    const style = marker.style;
    Object.entries( rect ).forEach( ([ key, val ]) => 
      style[ key ] = val + 'px'
    );
    style.borderColor = color;
    document.body.append( marker );
  } );
}

test( '.col-2 > span', 'red' );
test( '.single-line', 'green' );
test( '.col-6 > span', 'blue' );
.col-2{
  column-count: 2;
}
.col-6 {
  column-count: 6;
}
.single-line {
  width: 250px;
}

.position-marker {
  border: 1px solid;
  position: absolute;
  pointer-events: none;
}
div[class^=col-] {
  margin-bottom: 12px;
}
body { margin-bottom: 102px; }
body > .as-console-wrapper { max-height: 90px; }
<div class="col-2">
  <h1>Hello</h1>
  <span>text text text texttext text text text text text text text text text text text text text text text text text text text text texttext texttext text text text text text text text text text text text text text text text text text text text text text text text text text text text text texttext text text texttext texttext text text text text text text text
</span>
</div>
<div class="col-2 single-line">single line test for Firefox and Safari</div>
<div class="col-6">
  <span>text text text texttext text text text text text text text text text text text text text text text text text text text text texttext texttext text text text text text text text text text text text text text text text text text text text text text text text text text text text text texttext text text texttext texttext text text text text text text text
</span>
</div>

关于javascript - 在 chromium/puppeteer 中获取按列数拆分的 div 边界框,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59079727/

相关文章:

javascript - 右 css 递减 4.5px 宽度递减 10px

javascript - 幻灯片效果不工作

html - 创建在每一行上点缀的文本区域

node.js - Puppeteer 无法截图

javascript - 如何在 Puppeteer 中重新加载页面?

puppeteer - Jasmine 使用 jest-circus 后未定义错误

javascript - webgl earth javascript 中的 fancybox html

javascript - 如何使用javascript将不可选择的文本添加到svg而不进行初始选择?

html - 我可以使用直接 HTML/CSS 网站的模板部分吗?

html - 在边框框内居中内容