JavaScript — Усекает строку innerHTML после N чисел символов, удаляя внутри нее любой тег или символ

#javascript #html

Вопрос:

Я пытался добавить три точки после 130 символов строки, которые были взяты из DIV с помощью метода JavaScript innerHTML. Внутри innerHTML может быть больше тегов и атрибутов, которые необходимо пропустить при подсчете. Также необходимо сохранить и повторно назначить усеченный HTML в тот же DIV после завершения операции.

Вот несколько примеров входной строки и ожидаемых результатов —

Вход 1:

 <p>There are many <i>variations</i> of passages of <b>Lorem Ipsum</b> available, but the majority have suffered alteration in some form, by injected humour, or randomised words that don't look even slightly believable.</p>
 

Результат 1:

  <p>There are many <i>variations</i> of passages of <b>Lorem Ipsum</b> available, but the majority have suffered alteration in some form, by injecte...</p>
 

вход 2:

 <p><span class="header3">There are many variations of passages of Lorem Ipsum available, but the majority have suffered alteration in some form, by injected humour, or randomised words that don't look even slightly believable.</span></p>
 

результат 2:

 <p><span class="header3">There are many variations of passages of Lorem Ipsum available, but the majority have suffered alteration in some form, by injecte...</span></p>
 

Вход 3:

 <h4><span class="santral-pullquote-32"><span class="body-regular">There are many variations of passages of Lorem Ipsum available, but the majority have suffered alteration in some form, by injected humour, or randomised words that don't look even slightly believable.</span></span></h4>
 

Результат 3:

 <h4><span class="santral-pullquote-32"><span class="body-regular">There are many variations of passages of Lorem Ipsum available, but the majority have suffered alteration in some form, by injecte...</span></span></h4>
 

Использование следующей функции Тип ввода 1 работает только, но не другие:

 function cutString = (str) => {
    let stringCount = 0;
    let keepCounting = true;
    let ans = '';
    let openTags = [];
    for (let i = 0; i < str.length; i  ) {
        if (str[i] == "<") {
            keepCounting = false;
            if (str[i   1] != `/`) openTags.push(str[i   1])
            continue;
        }
        if (str[i] == ">") {
            keepCounting = true;
            if (str[i - 2] == `/`) openTags.splice(openTags.indexOf(str[i - 2]), 1)
            continue;
        }
        if (keepCounting) stringCount  
        if (stringCount == 131) {
            ans = str.slice(0, i);
            break;
        }
    }
    openTags.forEach(tag => ans = ans   `amp;#8230;</${tag}>`);
    return ans;
}
 

Я использую чистый JavaScript (без jQuery).
Любая помощь будет очень признательна!
Заранее спасибо.

Ответ №1:

вы можете попробовать это. Обратите внимание, что этот код напрямую обновляет html, если вы хотите сохранить исходное содержимое, клонировать узел, с которым вы хотите играть, и использовать клонированную версию для запуска обрезки:

 function map_node(f_objNode,f_currLimit){
    for(var i=0;i<f_objNode.childNodes.length;i  ){
      var l_node = f_objNode.childNodes[i];
      if(f_currLimit == 0){ //max length exceeded, remove node
        l_node.remove();
        i--; //move index backwards to account for the deleted node
        continue;
      }else if(l_node.nodeType == 3){ //textnode
        var l_strText = l_node.nodeValue;
        if((f_currLimit - l_strText.length) < 0){ //the text length
                                                  //exceeds the limit
                                                  //trim and 0 the limit
          l_node.nodeValue = l_strText.substring(0,f_currLimit)   '...';
          f_currLimit = 0;
        }else{ //max length is below the text length, update the limit
          f_currLimit -= l_strText.length
        }
      }
      //process the children of the node,
      //you can add check here to skip the call if no children
      f_currLimit = map_node(l_node,f_currLimit);
  }
  return f_currLimit
}

//this is how you use it.
function test(){
  var l_textLimit = 100; //your limit
  var l_div   = document.getElementById("test-div"); //your node
  var l_data  = map_node(l_div,l_textLimit); //parse the shit out of it
  //not really used, but if you replace the 
  //the limit integer with {} you can add postprocessing
  console.log(l_data)
}
 

в качестве примечания обратите внимание на синтаксический анализ как способ маркирования html. Это, безусловно, имеет свое применение, но может стать довольно сложным, если вы хотите сохранить структуру узла. В таких случаях проще и эффективнее работать с DOM напрямую. В этом направлении также есть проблемы — большие деревья DOM (sub)не являются идеальной целью для рекурсивной обработки, поэтому вам нужно выбрать свой подход для конкретного контекста.

Комментарии:

1. с помощью вашей функции HTML-текст усекается на 43 символа при ограничении 60.

2. Ввод: <p><p><span class=»header3″>Доступно множество вариантов отрывков Lorem Ipsum, но большинство из них претерпели изменения в той или иной форме, путем введения юмора или случайных слов, которые выглядят даже немного неправдоподобно.<span class=»header3″></span></p>

3. Вывод: <p><p><span class=»header3″>Существует множество вариантов пассажей Lo…<span class=»header3″></span></p>

4. Может быть, там были пробелы, как в то время как консоль — f_objNode.childNodes; его показывают мне как — три массива, текст, p, текст. Когда я печатаю 1 — й или последний массив на консоли, он возвращает мне что-то вроде — «n » и «nn » для последнего

5. Я не знаю, вы должны исправить это сами, я попробовал в jsfiddle, и это работает достаточно хорошо, чтобы проиллюстрировать принцип.