前几天,我正在开发 JSON 模式生成器,并希望在
我做了一些研究,发现了多种方法:
我一个都不喜欢!第一个看起来不清晰 - 并且与我已经为我的
第二个需要一堆 JavaScript 来维护有序列表:动态添加/删除
所以我最终创建了一个混合体。
它是动态生成的 SVG,存储为 CSS 自定义属性 — 并用作背景图像,从其父
让我们开始吧。
一、main方法:
lineNumbers(element, numLines = 50, inline = false)
元素是
接下来,我们为自定义属性定义一个前缀:
const prefix = '--linenum-';
在继续之前,我们检查是否重新使用任何现有财产:
if (!inline) { const styleString = document.body.getAttribute('style') || ''; const regex = new RegExp(`${prefix}[^:]*`, 'g'); const match = styleString.match(regex); if (match) { element.style.backgroundImage = `var(${match[0]})`; return; } }
接下来,我们从元素中提取样式,使用相同的字体系列、字体大小、行高等渲染 SVG。:
const bgColor = getComputedStyle(element).borderColor; const fillColor = getComputedStyle(element).color; const fontFamily = getComputedStyle(element).fontFamily; const fontSize = parseFloat(getComputedStyle(element).fontSize); const lineHeight = parseFloat(getComputedStyle(element).lineHeight) / fontSize; const paddingTop = parseFloat(getComputedStyle(element).paddingTop) / 2; const translateY = (fontSize * lineHeight).toFixed(2);
我们的财产也需要一个随机 ID:
const id = `${prefix}${Math.random().toString(36).substr(2, 6)}`;
现在是时候渲染 SVG 了:
const svg = `<svg xmlns="http://www.w3.org/2000/svg"> <style> svg { background: ${bgColor}; } text { fill: hsl(from ${fillColor} h s l / 50%); font-family: ${fontFamily}; font-size: ${fontSize}px; line-height: ${lineHeight}; text-anchor: end; translate: 0 calc((var(--n) * ${translateY}px) + ${paddingTop}px); } </style> ${Array.from({ length: numLines }, (_, i) => `<text x="90%" style="--n:${i + 1};">${i + 1}</text>`).join("")} </svg>`;
让我们来分解一下:
在
最后一部分迭代从 numLines 创建的数组,并将
我们快到了!
要将生成的 SVG 用作 url() 属性,我们需要对其进行编码:
const encodedURI = `url("data:image/svg+xml,${encodeURIComponent(svg)}")`;
最后,我们在元素或文档主体上设置该属性:
const target = inline ? element : document.body; target.style.setProperty(id, encodedURI); element.style.backgroundImage = `var(${id})`;
就是这样!
还不错,只有 610 字节,经过缩小和压缩!
您可以在此处查看演示,并在此处下载完整脚本。
下面是一个简化的 Codepen,未使用内联属性逻辑:
有优点和缺点吗?当然有!
就我个人而言,对于我当前的项目,我需要一种简单、清晰的方法来将行号添加到
此方法不依赖于操作 DOM。行号生成为单个 SVG,存储在 CSS 自定义属性中。
由于行号是背景图像的一部分,它们会自动随文本内容滚动,无需手动同步逻辑。
通过将生成的 SVG 存储在 CSS 自定义属性中,它可以在多个元素之间重复使用。这意味着如果多个元素需要相同的行号,它们都可以引用相同的自定义属性,从而避免冗余的 SVG 生成。
屏幕阅读器和辅助技术更容易访问有序列表,而基于 SVG 的行号可能会被忽略或误解。
对有序列表中的各个行号进行样式设置和交互非常简单。相比之下,SVG 方法使得自定义或向特定行号添加交互性变得更加困难。
SVG 和 CSS 自定义属性可能无法在所有浏览器中一致地呈现 - 当前的实现在 Safari 中存在问题,我们需要从 translateY 中扣除 (paddingTop / 10)。
有序列表可以更灵活地处理动态内容更新,例如添加或删除行,而 SVG 方法可能需要重新生成并重新应用整个背景图像。
以上是使用 SVG 的