gpt4 book ai didi

javascript - HTML : Prevent line breaks before some punctuation characters preceeded by a whitespace

转载 作者:行者123 更新时间:2023-11-29 18:39:30 25 4
gpt4 key购买 nike

在法语版式约定中,很少有标点符号像 ;:? 前面必须有一个空格。当标点位于其 HTML 容器的边界时,这会导致不需要的换行。

Voulez-vous coucher avec moi ce soir ? Non, merci.

成为

Voulez-vous coucher avec moi ce soir 
? Non, merci.

目标是这样得到的:

Voulez-vous coucher avec moi ce 
soir ? Oui, bien sûr.

我没有找到任何方法来避免使用 CSS 在这些字符之前换行。此外:

  • 由于现有数据和人体工程学限制,在每次出现之前手动添加   不是一种选择。
  • 使用 CSS whitespace: nowrap; 不是一种选择,因为它必须在所有其他情况下发生。

我正在考虑使用运行 str.replace("?", " ?"); 的全局 javascript 函数,但我无法弄清楚一些事情:

  • 如何以及何时触发它
  • 如何选择合适的标签
  • 如何仅替换 innerText(即不是属性内容)

有什么建议吗?

注意: Whitespace before some punctuation characters in French: is there a CSS way to avoid lines breaking?共享相同的目标,但具有我这里没有的纯 CSS 约束。

最佳答案

理想情况下,您应该用硬空间替换服务器端,而不是客户端,因为如果您在客户端执行此操作,您将遇到以下问题当您更新内容时,内容会回流,这会导致可察觉的闪烁/移动。

大多数情况下,您会在文本节点中遇到此问题,例如:

<p>Voulez-vous coucher avec moi ce soir ? Non, merci.</p>

这是一个元素(p 元素),里面有一个文本节点。

可能将它放在一个文本节点中的空格和另一个文本节点中的标点符号的位置:

<p><span>Voulez-vous coucher avec moi ce soir </span>? Non, merci.</p>

“Voulez-vous coucher avec moi ce soir”和空格在一个文本节点中(在 span 内),但标点符号在另一个文本节点中(在 p 中)。我假设这种情况非常罕见,我们无需担心。

在文本节点中处理它相对容易:

fixSpaces(document.body);

function fixSpaces(node) {
switch (node.nodeType) {
case 1: // Element
for (let child = node.firstChild;
child;
child = child.nextSibling) {
fixSpaces(child);
}
break;

case 3: // Text node
node.nodeValue = node.nodeValue.replace(/ ([;?!])/g, "\u00a0$1");
break;
}
}

实例:

// Obviously, you wouldn't have this in a `setTimeout` in your
// real code, you'd call it directly right away
// as shown in the answer
console.log("Before...");
setTimeout(() => {
fixSpaces(document.body);
console.log("After");
}, 1000);

function fixSpaces(node) {
switch (node.nodeType) {
case 1: // Element
for (let child = node.firstChild;
child;
child = child.nextSibling) {
fixSpaces(child);
}
break;

case 3: // Text node
node.nodeValue = node.nodeValue.replace(/ ([;?!])/g, "\u00a0$1");
break;
}
}
p {
font-size: 14px;
display: inline-block;
width: 220px;
border: 1px solid #eee;
}
<p>Voulez-vous coucher avec moi ce soir ? Non, merci.</p>

你会在 script 中找到它body 末尾的标签, 就在收盘前 </body>元素。

但再次强调:如果您可以在服务器端执行此操作,那会更好,以避免回流。


如果我们想尝试处理一个 Text 节点以空格结尾而下一个以标点符号开头的情况,如我上面所示:

<p><span>Voulez-vous coucher avec moi ce soir </span>? Non, merci.</p>

...一种方法是获取所有文本节点的数组,然后查看是否有一个以空格结尾,下一个以标点符号开头。这是不完美的,因为它不会尝试处理以空格结尾的文本节点位于 block 元素末尾的情况(例如,标点符号在视觉上总是位于不同的行上),但它可能聊胜于无。唯一的缺点是你最终可能会在 block 元素的末尾有一个额外的硬空间。

fixSpaces(document.body);

function gatherText(node, array = []) {
switch (node.nodeType) {
case 1: // Element
for (let child = node.firstChild;
child;
child = child.nextSibling) {
array = gatherText(child, array);
}
break;

case 3: // Text node
array.push(node);
break;
}
return array;
}

function fixSpaces(node) {
const texts = gatherText(node);
for (let i = 0, len = texts.length; i < len; ++i) {
const text = texts[i];
const str = text.nodeValue = text.nodeValue.replace(/ ([;?|])/g, "\u00A0$1");
if (i < len - 1 && str[str.length - 1] === " " && /^[;?!]/.test(texts[i + 1].nodeValue)) {
// This node ends with a space and the next starts with punctuation,
// replace the space with a hard space
text.nodeValue = str.substring(0, str.length - 1) + "\u00A0";
}
}
}

console.log("Before...");
setTimeout(() => {
fixSpaces(document.body);
console.log("After");
}, 1000);

function gatherText(node, array = []) {
switch (node.nodeType) {
case 1: // Element
for (let child = node.firstChild;
child;
child = child.nextSibling) {
array = gatherText(child, array);
}
break;

case 3: // Text node
array.push(node);
break;
}
return array;
}

function fixSpaces(node) {
const texts = gatherText(node);
for (let i = 0, len = texts.length; i < len; ++i) {
const text = texts[i];
const str = text.nodeValue = text.nodeValue.replace(/ ([;?|])/g, "\u00A0$1");
if (i < len - 1 && str[str.length - 1] === " " && /^[;?!]/.test(texts[i + 1].nodeValue)) {
// This node ends with a space and the next starts with punctuation,
// replace the space with a hard space
text.nodeValue = str.substring(0, str.length - 1) + "\u00A0";
}
}
}
p {
font-size: 14px;
display: inline-block;
width: 220px;
border: 1px solid #eee;
}
<p><span>Voulez-vous coucher avec moi ce soir </span>? Non, merci.</p>


将您的问题映射到上述内容:

How and when triggering it

把它放在 scriptbody 末尾的元素很早就触发它,但是在内容位于 DOM 中并因此准备好我们对其进行操作之后。

How to select the appropriate tags

我们忽略标签并在文本节点级别工作。

How to replace innerText only (ie not properties content)

通过处理文本节点级别。属性不是文本节点,因此我们不处理它们。

关于javascript - HTML : Prevent line breaks before some punctuation characters preceeded by a whitespace,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58257080/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com