【问题标题】:Split multiline text into specific-width lines将多行文本拆分为特定宽度的行
【发布时间】:2021-07-29 13:40:55
【问题描述】:

我一直在尝试使用不同宽度的多个段落,但每次换行时,后面的行都会进入一个新段落<p></p>。我需要其中四个,我以后可以独立设计。 这是我想要实现的截图,例如:

here is the original question where I found the original script.

我想做的事:

我已经设法对其进行了改编并对其进行了相当多的理解,以使其在线条都相同的情况下工作。基本上:

 <p style="width:700px">I am some ra</p>
 <p style="width:700px">ndom text. I</p>
 <p style="width:700px">am Some text</p>
 <p style="width:700px">.blabla</p>

但现在我面临一个问题:

我想为我的 css 中的各个行指定不同的宽度,以便脚本完美地打破它们。换句话说:一行文本占据了div paragraph 的所有宽度,剩余的文本移动到另一个段落中(例如#text2),直到我们达到四个div paragraphs.

类似的东西:

<p style="width:50px">I am some ra</p>
<p style="width:900px">ndom text. I</p>
<p style="width:800px">am Some text</p>
<p style="width:1000px">.blabla</p>

编辑: 到目前为止有一些进展。文本似乎与之前段落的宽度有关。

这里是项目:

    var p = document.getElementById("p");
    var menu = document.getElementsByClassName("menu");
    var width = p.clientWidth;
    var parent = p.parentNode;
    var line = document.createElement("span");
    line.style.display = "inline-block";
    line.style.visibility = "hidden";
    var content = p.innerHTML;
    document.body.appendChild(line);
    var start = 0;
    var i = 1;
    let run = 1;
    while (i < content.length) {
      line.innerHTML = content.substring(start, i);
      console.log(i + " " + content.length);
      console.log("#text" + run + " width: " + menu[run].clientWidth);
      console.log("run: " + run);
      if (line.clientWidth > menu[run + 1].clientWidth) {
        var newp = document.createElement("p");
        newp.id = "text" + run;
        newp.className = "menu";
        newp.innerHTML = content.substring(start, i - 1);
        parent.insertBefore(newp, p);
        start = i - 1;
        i = start + 1;
        run++;
      } else {
        i++;
      }
    }
    newp = document.createElement("p");
    newp.id = "textbis" + run;
    newp.className = "menu";
    newp.innerHTML = content.substring(start);
    parent.insertBefore(newp, p);
    parent.removeChild(p);
div {
  word-break: break-all;
  background-color: lightblue;
  width: 700px;
}
p {
  background-color: lightgreen;
}
#text0 {
  width: 50px;
}

#text1 {
  width: 50px;
}

#text2 {
  width: 200px;
}

#text3 {
  width: 500px;
}

#text4 {
  width: 700px;
}
    <div>
      <p class="menu" id="text1"></p>
      <p class="menu" id="text2"></p>
      <p class="menu" id="text2"></p>
      <p class="menu" id="p">
        Lorem ipsum dolor sit amet, consectetur adipisicing elit. Saepe,
        aliquam? Lorem ipsum dolor sit amet consectetur adipisicing elit.
        Quibusdam quaerat iste earum quos eligendi atque aliquam veniam facilis
        quis ducimus. Lorem ipsum dolor sit amet consectetur adipisicing elit.
        Iure, quisquam! Temporibus consequuntur laboriosam quos odio maxime
        iusto at dolore quod ipsa eaque voluptas mollitia, vel odit inventore
        sapiente aut!
      </p>
    </div>

【问题讨论】:

  • 代码sn-p有错误。它不起作用。你可能想解决这个问题。
  • 好像是死循环什么的;日志显示i 不断增加,content.length 为常数 437。nombre 变为 0 1 2,然后返回 0。当i 达到 580531 时,我停止了。
  • 正如@HereticMonkey 提到的,现在你有了另一个:) 作为旁注,我并没有过多关注这个问题本身,因为它看起来有点模棱两可,并且可以使用一些改进。这就是为什么我想看到代码在起作用。认为它可以画出比描述更好的画面。
  • 编辑了代码,使其不会循环或做任何奇怪的事情。现在可能更清楚了!谢谢
  • 为什么不呢?这就是 字面意思 HTML 的用途:标记数据。如果这不是在主页加载后加载的附加内容,则不要在这些句子周围放置段落元素,然后在事实非常接近“做 html 错误”之后尝试这样做。

标签: javascript html css


【解决方案1】:

就性能而言,这可能不是最佳选择,但这是一种方法。

let textarea = document.querySelector("textarea");
let output   = document.querySelector("textarea + div");

let widths = [100, 450, 400, 500, 9999];

textarea.addEventListener("input", () => {
    output.innerHTML = null;
    console.time("split took");
    let lines = splitTextByLineWidths(textarea.value, widths);
    console.timeEnd("split took");
    lines.forEach((line, i) => {
        let p = document.createElement("p");
        if (widths[i] < window.innerWidth) {
            p.style.width = widths[i] + "px";
        }
        p.textContent = line;
        output.append(p);
    });
});
textarea.dispatchEvent(new Event("input"));

function splitTextByLineWidths(text, lineWidths) {
    let lines = [];
    let renderer = document.createElement("div");
    renderer.style.position = "absolute";
    renderer.style.left = window.innerWidth * -3 + "px";
    renderer.style.top = window.innerHeight * -3 + "px";
    document.body.appendChild(renderer);
    lineWidths.forEach(lineWidth => {
        let measure = document.createElement("div");
        measure.style.display = "table";
        measure.textContent = "dummy";
        renderer.appendChild(measure);
        let lineHeight = measure.offsetHeight;
        let activeText = text;
        measure.textContent = activeText;
        measure.style.width = lineWidth + "px";
        let height = measure.offsetHeight;
        while (height > lineHeight) {
            activeText = activeText.slice(0, -1);
            measure.textContent = activeText;
            height = measure.offsetHeight;
        }
        lines.push(activeText);
        text = text.slice(activeText.length);
    });
    renderer.remove();
    return lines;
}
textarea + div {
    background-color: lightblue;
    padding: 1em;
}
textarea + div p {
    background-color: peachpuff;
}
<textarea cols="100" rows="6">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque varius nisi purus, in dignissim justo egestas et. Suspendisse suscipit, metus vitae facilisis cursus, diam est malesuada tellus, eu viverra risus sapien nec neque.</textarea>
<div></div>

可以通过使用更智能的方式修剪文本来进一步改进此方法。目前,它正在修剪单个字符并检查文本是否溢出第一行。这是一项昂贵的操作。

人们可以设计一种方法来增加修剪长度,而不是单向(仅修剪),当文本下溢宽度时,可以双向(修剪和增长/放回)。

【讨论】:

  • 谢谢,确实,这是一种解决方法。到目前为止,我还用我的进度编辑了我的代码 sn-p。这很奇怪,我一定错过了一些东西,因为第一个 p 似乎被忽略了......
  • @pual 我认为您应该将您的问题与实现细节隔离开来。您有一个长/多行文本,并且您希望将其拆分为长度不同的单独行。这可以在单个函数中解决。你的 sn-p 很复杂。文本和宽度的来源无关紧要。这些是实现细节。如果它们确实重要,您应该提供有关页面的更多详细信息,并通过将文本分成几行来解释您正在尝试做什么。另请阅读XY problem。这样以后你就免去很多麻烦了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-04-25
  • 1970-01-01
  • 2011-12-20
  • 2013-08-28
  • 2020-12-12
  • 2014-06-09
  • 1970-01-01
相关资源
最近更新 更多