编码建议:dom操作-将文本拆分为动态范围

时间:2018-08-05 11:35:24

标签: javascript dom ecmascript-6

有关更新的问题,请参见下面的编辑帖子

我已经解决了dom操纵问题,但是我不相信这是解决它的最干净,最清晰的方法。

旧问题:将innerHTML从一组元素转换为三个范围,并用新转换的范围替换每个元素的innerHTML。

例如:

<h1>This is awesome<h1>
<h1>
  <span class="color-1">This</span>
  <span class="color-2">is</span>
  <span class="color-3">awesome</span>
</h1>

我已经使用了很多切片和连接以及递归函数,但是我认为用更少的代码可能会得到相同的结果,例如,使用更多的es6数组辅助方法。你能帮我吗?

要求

  1. InnerHTML单词应计算并除以三
  2. 如果有残差,则最后一个跨度应包含最少的单词数,但与第一个(和第二个)跨度相比,单词的个数不得少于1。
  3. 所以有15个单词,每个跨度包含5个
  4. 由17个单词组成,前2个跨度应包含6个单词,最后一个有5个
  5. 只有2个单词,第一个和第二个跨度应包含每个1个单词,最后一个跨度为空。

    const elements = Array.from(document.querySelectorAll("h1, h2 , h3, h4"));
    convertElements(elements);
    
    function convertElements(elements) {
      const textsInsideElements = elements.map(htmlElement => htmlElement.innerHTML);
      textsInsideElements.forEach((text, index) =>
                            convertToSeparateSpans(elements, text, index));
    }
    
    function convertToSeparateSpans(elements, string, index) {
      const wordsPerSpan = calculateWordsPerSpan(string, 3);
      const wordParts = pushWordSpansToSeparateArrays([], string, wordsPerSpan, -1);
      const joinedTextSpans = wordsToSpanElements(wordParts);
      elements[index].innerHTML = joinedTextSpans;
    }
    
    function calculateWordsPerSpan(string, totalSpans) {
      const totalLength =  string.split(' ').length;
      const residual = totalLength % totalSpans;
      const firstPart = residual === 0 ? 
                          totalLength / totalSpans : Math.ceil(totalLength / totalSpans);
      const middlePart = residual === 1 ? firstPart * 2 - 1 : firstPart * 2;
      const endPart = totalLength;
      return [].concat(firstPart).concat(middlePart).concat(endPart);
    }
    
    function pushWordSpansToSeparateArrays(result, string, stringPartials, index) {
      const firstIteration = index === -1;
      const indexOutOfBounds = stringPartials[index + 1] === undefined;
      const stringToArr = string.split(' ');
      const firstString = stringToArr.slice(0, stringPartials[index + 1]).join(' ');
      const subsequentString = stringToArr
                                 .slice(stringPartials[index], stringPartials[index + 1])
                                 .join(' ');
      if(firstIteration) {
        result.push(firstString);
        pushWordSpansToSeparateArrays(result, string, stringPartials, index + 1)
        return result;
      } else if (!firstIteration && !indexOutOfBounds) {
        result.push(subsequentString);
        pushWordSpansToSeparateArrays(result, string, stringPartials, index + 1);   
      }
    }
    
    function wordsToSpanElements(wordParts) {
      const spanArray = wordParts.map((part, index) => 
      `<span class="color-${index+1}">${part}</span>`);
      return spanArray.join(' ');
    }
    

编辑

在@Nathan Stockton的帮助下,我终于用以下代码格式化了代码:

    function pushWordSpansToSeparateArrays(string) {
      const splitString = string.trim().split(" ");
      const hasResidual1 = splitString.length%3 === 1;
      const firstThird = Math.ceil(splitString.length/3);
      let secondThird = hasResidual1 ? firstThird * 2 - 1  : firstThird * 2;
      return []
        .concat(splitString.slice(0, firstThird).join(' '))
        .concat(splitString.slice(firstThird, secondThird).join(' '))
        .concat(splitString.slice(secondThird, splitString.length).join(' '));
    }
    const test = "This is a long string";
    console.log(pushWordSpansToSeparateArrays(test))
    // output ["This is", "a long", "string"]

这种方法的问题在于它不能重复使用超过3个部分。

新问题:是否有一种方法可以使此函数具有通用性,使其能够根据参数将单词分为任意数量的部分,例如pushWordSpansToSeparateArrays(string,totalParts);

2 个答案:

答案 0 :(得分:1)

接受2条回复-我现在上床睡觉,希望它能起作用!

String.prototype.splitInto = function (parts) {
  const splitString = this.trim().split(" ");
  obResponse = {};
  obResponse.values = [];
  var chunkSize = Math.floor(splitString.length/(parts));
  var spares = splitString.length%parts;
  var start = 0;
  for(var i = 0; i < parts; i++) {
    obResponse.values[i] = splitString.slice(start, start+chunkSize+(spares>i?1:0));
    start = start+chunkSize+(spares>i?1:0);
  }
  return obResponse;
}
var segments = "test a b k l m n o ".splitInto(3);
console.log(segments.values);

答案 1 :(得分:0)

这似乎要短得多,可以适应您的需求(我认为是):

String.prototype.splitInto3 = function () {
  const splitString = this.trim().split(" ");
  var firstThird = Math.ceil(splitString.length/3);
  var secondThird = splitString.length-Math.floor((splitString.length-firstThird)/2);
  var obResponse = {
    firstSegment: splitString.slice(0, firstThird),
    secondSegment: splitString.slice(firstThird, secondThird),
    thirdSegment: splitString.slice(secondThird, splitString.length)
  }
  return obResponse;
}
var segments = "test a b c d e f g h i j k l m n o ".splitInto3();
console.log("First third ("+segments.firstSegment.length+"): "+segments.firstSegment);
console.log("Second third ("+segments.secondSegment.length+"): "+segments.secondSegment);
console.log("Third third ("+segments.thirdSegment.length+"): "+segments.thirdSegment);

或作为数组

String.prototype.splitInto3 = function () {
  const splitString = this.trim().split(" ");
  var firstThird = Math.ceil(splitString.length/3);
  var secondThird = splitString.length-Math.floor((splitString.length-firstThird)/2);
  var obResponse = [splitString.slice(0, firstThird), splitString.slice(firstThird, secondThird), splitString.slice(secondThird, splitString.length)]
  return obResponse;
}
var segments = "test a b c d e f g h i j k l m n o ".splitInto3();
console.log("First third ("+segments[0].length+"): "+segments[0]);
console.log("Second third ("+segments[1].length+"): "+segments[1]);
console.log("Third third ("+segments[2].length+"): "+segments[2]);