有没有办法从`<div>`-Element中提取单行?

时间:2015-05-04 18:57:20

标签: javascript html css hyphenation

看看这个<div> - 元素:

<div id="text">Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque pena&shy;tibus et magnis dis parturient montes, nascetur ridiculus mus.</div>

和这个css:

div#text {
    font-family: Arial;
    font-size: 16px;
    width: 200px;
}

当渲染这个div时,它被分成许多行,可能看起来像这个块:

  

Lorem ipsum dolor sit amet,
  consectetuer adipiscing elit。
  Aenean commodo ligula
  eget dolor。 Aenean massa。
  Cum sociis natoque pena-
  tibus et magnis dis
  产妇montes,nascetur
  嘲笑

有没有办法使用Javascript提取这个div内容的第6行?这意味着,我想要一个函数,我传递值3,然后它返回»tibus et magnis dis«。这可能吗?如果是这样,怎么办呢?

“penatibus”这个词中的软连字符(&shy;)使得这个词被分成两部分。

以类似的方式,考虑css-property hyphen

div#text {
    hyphens: auto;
}

这会使渲染机连接文本,而无需插入破折号或&shy; - 实体。

请记住,文本中没有换行符或<br>或任何其他标记将文本拆分为多行。它只是渲染机器的自动换行算法和css-styles以及texttring本身,它们负责将哪些单词写入哪一行。

这也是此问题与this不同的原因。

这个问题也与this one不同,因为那里发布的解决方案忽略了连字符的影响。

还要想到连字(就像f后跟i一样,许多字体被新的字形替换,fi,比正常f稍微短一点,接着是正常情况。这可能会影响自动换行和但是当你将文本的每个字符放入一个<span>元素中以便能够读取所有这些元素的位置时,你就不会看到f和我被其较短的连字fi所取代,所以在所有情况下,此方法都不会返回正确的结果。

1 个答案:

答案 0 :(得分:2)

I guess you could trick a bit, and copy the width of the existing element, and then add word per word to see if the height of the new element changes, then increase the line.

I wrote a basic version of this. This only takes into account the width of the div element, none of the other styles (like font-size, letter-spacing, ... for that, you could copy the css styles from the element you wish to get the line nr from)

function copyStyle(source, target) {
  var computedStyle = window.getComputedStyle(source, null),
    prop, obj = computedStyle, i, len, style = '';
  for (i = 0, len = computedStyle.length; i < len; i++) {
      prop = computedStyle[i];
      style += prop + ': ' + obj[prop] + ';';
  }
  target.style = style;
}

function extractHyphens(array) {
  var word, i, len, shyElement = document.createElement('span');
  shyElement.innerHTML = '&shy;';
  for (i = 0, len = array.length; i < len; i++) {
    word = array[i];
    if (word.indexOf(shyElement.innerHTML) >= 0) {
      word = word.split(shyElement.innerHTML);
      array.slice(i, 1, word);
    }
  }
}

function getLine(element, lineNr, callback, measuredWidth) {
  var hiddenElement,
    sourceElement = document.getElementById(element),
      textarea = document.getElementById('textarea'),
    lastHeight,
    outline = '',
    curline = -1,
    words, word;

  if (typeof measuredWidth === 'undefined' ||
    measuredWidth !== sourceElement.offsetWidth) {
    measuredWidth = sourceElement.offsetWidth;
    setTimeout(function() {
      getLine(element, lineNr, callback, measuredWidth);
    }, 100);
  } else {
    hiddenElement = document.createElement('div');
    words = sourceElement.innerHTML;
    words = words.split(' ');
    extractHyphens(words);
    copyStyle(sourceElement, hiddenElement);
    hiddenElement.style.visibility = 'hidden';
    // we don't want anything affecting the height of the "hidden" element
    hiddenElement.style.height = 'auto';
    delete hiddenElement.style['minHeight'];
    delete hiddenElement.style['maxHeight'];
    document.body.appendChild(hiddenElement);
    lastHeight = hiddenElement.offsetHeight;
    for (var i = 0, len = words.length; i < len; i++) {
      word = words[i];
      hiddenElement.innerHTML += word;
      if (lastHeight !== hiddenElement.offsetHeight) {
        curline++;
      }
      if (lineNr === curline) {
        outline += word + ' ';
      }
      hiddenElement.innerHTML += ' ';
      lastHeight = hiddenElement.offsetHeight;
      if (curline > lineNr) {
        break;
      }
    }
    document.body.removeChild(hiddenElement);
    setTimeout(function() {
      callback(element, outline);
    }, 0);
  }
}

function showResult(element, result) {
  alert(element + ': ' + result);
}

window.onload = function() {
  getLine('test', 1, showResult);
  getLine('test2', 6, showResult);
};
#test2 {
  width: 50px;
  font-size: 7px;
  padding: 3px;
}
div {
  padding: 5px;
}
<div id="test">lorem ipsum dolor sit amet, consectetuer adipiscing elit, aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque&shy;&raquo;penatibus&laquo; et magnis dis parturient montes, ascetur ridiculus mus.</div>
<div id="test2">lorem ipsum dolor sit amet, consectetuer adipiscing elit, aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, ascetur ridiculus mus.</div>