使用Javascript

时间:2016-10-31 21:54:55

标签: javascript html css

下面我写了一些代码,它在表格单元格中占用一些内容,如果它运行的话,将其截断为两行。当试图找到接近2个完整行的正确内容长度(但不会超过!)时,我采用对数方法(我认为)。我先把内容减半。然后我再次检查内容,加上或减去四分之一(一半的一半)。等

要求:

  • 截断文本末尾的省略号(...)。
  • 响应,策略应适用于动态宽度单元格

问题:

  • 在摘录中,我添加了一个导致3行的示例。我如何保证在合理接近2条完整线的同时降落在2条线上?
  • 我采用了对数方法,所以我不需要做一些像流行语,重新测试,弹出一个单词,重新测试等等。这仍然看起来太贵了,我怎么能改善这个?

document.querySelectorAll('.expand').forEach(td => {
  
  // get cell styles
  let styles = window.getComputedStyle(td);
  let lineHeight = parseInt(styles.lineHeight, 10);

  // create test element, mostly because td doesn't support max-height
  let el = document.createElement('div');
  el.innerHTML = td.innerHTML;
  el.style.maxHeight = (lineHeight * 2) + 'px';
  el.style.overflow = 'hidden';
  td.appendChild(el);

  // if scrollHeight is greater than clientHeight, we need to do some expand-y stuff
  if (el.scrollHeight > el.clientHeight) {
    
    // store content
    let content = el.innerHTML.trim(), 
        len = content.length;
    for (let i=Math.round(len*.5);; i=Math.round(i*.5)) {
      let over = el.scrollHeight > el.clientHeight;
      
      // if over 2 lines, cut by half
      // else increase by half
      over ? (len-=i) : (len+=i);
      
      // update innerHTML with updated content
      el.innerHTML = content.slice(0, len);
      
      console.log(i, len);
      
      // break if within margin of 10 and we landed under
      if (i<10 && !over) break;
    }
    
    td.innerHTML = `
      <div class="hide-expanded">${el.innerHTML.slice(0, -3).trim()}...</div>
      <div class="show-expanded">${content}</div>
      <button type="button">Toggle</button>`;
    
    td.querySelector('button').addEventListener('click', e => td.classList.toggle('expanded'))
  }
});
html {
  font-size: 14px;
  line-height: 24px;
  font-family: Helvetica, Arial, sans-serif;
}

table {
  border-collapse: collapse;
}

td {
  white-space: nowrap;
  padding: 1rem;
}

.expand {
  white-space: normal;
}

.expand:not(.expanded) .show-expanded,
.expand.expanded .hide-expanded {
  display: none;
}
<table>
  <tbody>
    <tr>
      <td class="expand">This is some content. This is some content. This is some content. This is some content. This is some content. This is some content. This is some content. This is some content. This is some content. This is some content. This is some content. This is some content. This is some content. This is some content. This is some content. This is some content. This is some content. This is some content. This is some content. This is some content. This is some content. This is some content. This is some content.</td>
    </tr>
  </tbody>
</table>

1 个答案:

答案 0 :(得分:0)

这个github回购是我能找到的最好(也是最简洁)的解决方案。我已经改编了一个解决方案。

https://github.com/dollarshaveclub/shave/blob/master/src/shave.js

export default function shave(target, maxHeight, opts) {
  if (!maxHeight) throw Error('maxHeight is required');
  let els = typeof target === 'string' ? document.querySelectorAll(target) : target;
  if (!('length' in els)) els = [els];

  const defaults = {
    character: '…',
    classname: 'js-shave',
    spaces: true,
  };
  const character = opts && opts.character || defaults.character;
  const classname = opts && opts.classname || defaults.classname;
  const spaces = opts && opts.spaces === false ? false : defaults.spaces;
  const charHtml = `<span class="js-shave-char">${character}</span>`;

  for (let i = 0; i < els.length; i++) {
    const el = els[i];
    const span = el.querySelector(`.${classname}`);

    // If element text has already been shaved
    if (span) {
      // Remove the ellipsis to recapture the original text
      el.removeChild(el.querySelector('.js-shave-char'));
      el.textContent = el.textContent; // nuke span, recombine text
    }

    // If already short enough, we're done
    if (el.offsetHeight < maxHeight) continue;

    const fullText = el.textContent;
    const words = spaces ? fullText.split(' ') : fullText;

    // If 0 or 1 words, we're done
    if (words.length < 2) continue;

    // Binary search for number of words which can fit in allotted height
    let max = words.length - 1;
    let min = 0;
    let pivot;
    while (min < max) {
      pivot = (min + max + 1) >> 1;
      el.textContent = spaces ? words.slice(0, pivot).join(' ') : words.slice(0, pivot);
      el.insertAdjacentHTML('beforeend', charHtml);
      if (el.offsetHeight > maxHeight) max = spaces ? pivot - 1 : pivot - 2;
      else min = pivot;
    }

    el.textContent = spaces ? words.slice(0, max).join(' ') : words.slice(0, max);
    el.insertAdjacentHTML('beforeend', charHtml);
    const diff = spaces ? words.slice(max + 1).join(' ') : words.slice(max);

    el.insertAdjacentHTML('beforeend',
      `<span class="${classname}" style="display:none;">${diff}</span>`);
  }
}