CSS Tips:CSS 如何穿透 SVG 的 use

CSS Tips 系列:

在当下,Web 应用或网站上随处可以看到 SVG 的应用。SVG 作为一种灵活的图像格式,已经成为现代 Web 设计的重要组成部分。它不仅允许图像在不同尺寸和分辨率下保持清晰度,还可以实现各种动画效果和交互效果。在许多情况下,我们会使用 SVG 的 <use> 元素来重复利用 SVG 图形,从而提高代码的可维护性和性能。

然而,有时候我们可能想对 <use> 元素的内容进行样式化,以便根据不同的场景呈现不同的外观。这就是 CSS 样式化 <use> 元素内容的重要性所在。通过 CSS,我们可以轻松地为 <use> 元素的图形内容添加样式,从而实现更灵活和多样化的视觉效果。

通过本教程,你将掌握一系列技术和技巧,使你能够灵活地样式化 <use> 元素的内容,从而为你的 Web 应用或网站增添更多的美感和吸引力。让我们开始吧,探索如何通过CSS创造出独特而精美的SVG图形效果!

始于大家最熟悉的地方

Icon 图标在 Web 应用或网站上随处可见,作为一名优秀的 Web 开发者,肯定拥有为 Web 应用或网站添加图标的技术,其中最为经典的应该是雪碧图(Sprites)技术。常见的雪碧图主要有位图和矢量图两种,而且矢量图占比越来越高。

虽然在 Web 应用或网站上使用 SVG 矢量雪碧图技术已非常成熟,但还是有不少小技巧不为人知。就在不久之前,有小伙伴私下问我,使用 SVG 的 <use> 引入的 Icon 图标,应该如何才能高度自定义,如何才能为其设置颜色,最终满足自己的需求?

在回答这些问题之前,先使用一个真实的案例向大家展示,Web 开发者平时使用 SVG 矢量图碰到的经典问题。继续以 SVG 雪碧图为例,当你使用 <use> 引用一个元素(例如 Icon 图标),代码可能如下所示:

XML 复制代码
<!-- 使用 symbol 定义和管理所需要的 icon 图标 -->
<svg class="icons sr-only">
    <symbol id="youtube" viewBox="0 0 1024 1024">
        <title>youtube</title>
        <g fill="#212121">
            <path d="M832 128 192 128c-105.6 0-192 86.4-192 192l0 384c0 105.6 86.4 192 192 192l640 0c105.6 0 192-86.4 192-192L1024 320C1024 214.4 937.6 128 832 128zM384 768 384 256l320 256L384 768z" fill="#212121" p-id="1710923637258-2546986_12356" />
        </g>
    </symbol>
    
    <symbol id="weibo" viewBox="0 0 1024 1024"></symbol>
  
    <!-- 其他 symbol -->
</svg>

<!-- 使用 use 将需要的 icon 引入到 Web 应用或网站中 -->
<ul class="nav">
    <li>
        <a href="#">
            <svg>
                <use href="#twitter" />
            </svg>
            <span>Twitter</span>
        </a>
    </li>
    <!-- 其他 li -->
</ul>

添加一些 CSS 代码:

CSS 复制代码
.nav {
    a {
      color: #767c8c;
      transition: color .3s ease-in;
      
        &:hover {
            color: #00b3b0;
        }
    }
    
    svg {
        display: block;
        width: 1.5em;
        height: 1.5em;
        fill: currentColor;    
    }
    
    use {
        fill: red;    
    }
}

你看到的效果如下:

Demo 地址:codepen.io/airen/full/...

你可能已经发现了,虽然我们在 CSS 中给 use 设置了 fill:red ,Icon 图标的颜色并没有被调整。接下来,我们来看看有哪些姿势可以为图标设置自己喜欢的颜色。

你需要知道 use 的内容在哪里

在寻找正确答案之前,你首先要知道的是:<use> 元素克隆来的内容到底放在哪里呢?

如果你打开浏览器的开发者工具,检查 <use> 元素的实例化内容(例如"Twitter"图标),你会发现在 <use> 元素下面有一个 #shadow-root

它是一个 Shadow DOM

从上面的截图中可以看出,SVG 的 <use> 元素所实例化的内容被克隆到一个由 <use> 元素"托管"的文档片段中。在这种情况下,<use> 元素被称为 Shadow Host。换句话说,<use> 元素克隆的内容以一种我们熟悉的 DOM 方式存在,但是存在于 <use> 元素托管的文档片段中,就像是一个影子一样。

对于开发者而言,不能像平时那样使用 CSS 或 JavaScript 来处理 <use> 元素托管的文档片段中的 DOM 元素,这是最令人关心的问题之一。开发者希望能够覆盖存在于 Shadow DOM 中的内容,特别是对于样式设置。

然而,实际情况并不如我们想象的那么简单。我们不能以熟悉的方式处理 Shadow DOM 中元素的样式。例如,下面这样的选择器无法选中 Shadow DOM 中的 DOM 元素:

CSS 复制代码
use path {
    fill: red;
}

这意味着,Web 开发者无法使用常规的 CSS 选择器来访问 Shadow DOM 中的元素。也是基于这个原因,不少 Web 开发者无法使用自己所掌握的 CSS 知识来解决相应的问题。如果你是这些 Web 开发者当中的一员,那么接下来的内容你将会获益不浅!

简单粗暴的删除法

以下面这个示例为例,它是 SVG 绘制的"咖啡"图标,并且存储在 <symbol> 中:

XML 复制代码
<svg xmlns="http://www.w3.org/2000/svg" class="sr-only">
    <symbol id="icon-coffee" viewBox="0 0 20 20">
        <title>icon-coffee</title>
        <path fill="#000" d="M15,17H14V9h3a3,3,0,0,1,3,3h0A5,5,0,0,1,15,17Zm1-6v3.83A3,3,0,0,0,18,12a1,1,0,0,0-1-1Z"/>
        <rect fill="#000" x="1" y="7" width="15" height="12" rx="3" ry="3"/>
        <path fill="#000" d="M7.07,5.42a5.45,5.45,0,0,1,0-4.85,1,1,0,0,1,1.79.89,3.44,3.44,0,0,0,0,3.06,1,1,0,0,1-1.79.89Z"/>
        <path fill="#000" d="M3.07,5.42a5.45,5.45,0,0,1,0-4.85,1,1,0,0,1,1.79.89,3.44,3.44,0,0,0,0,3.06,1,1,0,1,1-1.79.89Z"/>
        <path fill="#000" d="M11.07,5.42a5.45,5.45,0,0,1,0-4.85,1,1,0,0,1,1.79.89,3.44,3.44,0,0,0,0,3.06,1,1,0,1,1-1.79.89Z"/>
    </symbol>
</svg>

就上面的代码而言,如果你没有使用诸如 <use> 元素引用它的话,它是不会在 Web 上呈现的:

XML 复制代码
<svg class="icon" aria-hidden="true">
    <use href="#icon-coffee" />
</svg>

这个时候,你在浏览器中看到的是一个黑色的"咖啡"图标(包括咖啡杯和烟两个部分):

如果你希望得到是一个其他颜色的图标,例如 lime 颜色。我们是无法直接通过普通的 CSS 选择器来选中 <use> 元素的后代元素,但又为了需要改变图标颜色,很多 Web 开发者会考虑直接在 <symbol> 中修改元素的 fill 属性。例如:

XML 复制代码
<svg xmlns="http://www.w3.org/2000/svg" class="sr-only">
    <symbol id="icon-coffee" viewBox="0 0 20 20">
        <title>icon-coffee</title>
        <path fill="lime" d="M15,17H14V9h3a3,3,0,0,1,3,3h0A5,5,0,0,1,15,17Zm1-6v3.83A3,3,0,0,0,18,12a1,1,0,0,0-1-1Z"/>
        <rect fill="lime" x="1" y="7" width="15" height="12" rx="3" ry="3"/>
        <path fill="lime" d="M7.07,5.42a5.45,5.45,0,0,1,0-4.85,1,1,0,0,1,1.79.89,3.44,3.44,0,0,0,0,3.06,1,1,0,0,1-1.79.89Z"/>
        <path fill="lime" d="M3.07,5.42a5.45,5.45,0,0,1,0-4.85,1,1,0,0,1,1.79.89,3.44,3.44,0,0,0,0,3.06,1,1,0,1,1-1.79.89Z"/>
        <path fill="lime" d="M11.07,5.42a5.45,5.45,0,0,1,0-4.85,1,1,0,0,1,1.79.89,3.44,3.44,0,0,0,0,3.06,1,1,0,1,1-1.79.89Z"/>
    </symbol>
</svg>

这种方式可以使你得到一个绿色的图标。

甚至你可能会考虑,将 <symbol> 中绘制图形元素的样式属性都从元素中删除。例如,移除上面示例代码中 <rect><path> 元素的 fill 属性,然后在 <use> 元素上应用一个 fill 属性,使其后代元素继承该属性:

XML 复制代码
<svg xmlns="http://www.w3.org/2000/svg" class="sr-only">
    <symbol id="icon-coffee" viewBox="0 0 20 20">
        <title>icon-coffee</title>
        <path  d="M15,17H14V9h3a3,3,0,0,1,3,3h0A5,5,0,0,1,15,17Zm1-6v3.83A3,3,0,0,0,18,12a1,1,0,0,0-1-1Z"/>
        <rect  x="1" y="7" width="15" height="12" rx="3" ry="3"/>
        <path  d="M7.07,5.42a5.45,5.45,0,0,1,0-4.85,1,1,0,0,1,1.79.89,3.44,3.44,0,0,0,0,3.06,1,1,0,0,1-1.79.89Z"/>
        <path  d="M3.07,5.42a5.45,5.45,0,0,1,0-4.85,1,1,0,0,1,1.79.89,3.44,3.44,0,0,0,0,3.06,1,1,0,1,1-1.79.89Z"/>
        <path  d="M11.07,5.42a5.45,5.45,0,0,1,0-4.85,1,1,0,0,1,1.79.89,3.44,3.44,0,0,0,0,3.06,1,1,0,1,1-1.79.89Z"/>
    </symbol>
</svg>

<svg class="icon" aria-hidden="true">
    <use href="#icon-coffee" fill="lime" />
</svg>

这种方式你同样可以获得所需要的图标。但问题来了。

首先,fill 将被 <use> 的所有后代元素继承,即使你可能不想对所有后代元素进行样式化。也就是说,如果 <use> 内只有一个元素,或者你只需要一个单色图标,这种方式不会有任何问题。反之,如果 <use> 内有多个元素,并且是一个彩色图标(哪怕是两种颜色),这种方式会使你得不到最终想要的结果。

其次,你的 SVG 代码可能是通过诸如 Figma 图形设计软件导出或从设计师那里获得,或从第三方平台获得,并且出于任何原因,你可能没有权限或机会修改 SVG 代码。那么上面这两种方式也无法让你获得预期的图标。即使你可以有权限编辑 SVG 代码,我个人也强烈建议你不要这样做。因为:

  • 在大多数情况下,这些属性的值都是黑色(我们这里讨论的是 fill 属性),可以称为浏览器的默认值。一旦你移除这些属性,你不得不重置它们,否则它将以黑色形式存在,除非你刚好需要

  • 你可能需要重置所有值,例如 fillstrokestroke-width

也就是说,我们应该找到一些更合理的方式对 <use> 元素的内容进行样式化处理。

利用 CSS 的继承特性

首先,我们知道,use 元素的内容会继承来自 use 的样式。只不过我们所熟悉的选择器无法轻易让你穿透 Shadow DOM,选中 use 的后代元素。但我们可以利用 CSS 样式的继承(inherit)特性,让外部样式声明的属性样式覆盖来自 <use> 的继续值。

继续以上面的代码为例,我们希望得到不同颜色的图标:

XML 复制代码
<svg xmlns="http://www.w3.org/2000/svg" class="sr-only">
    <symbol id="icon-coffee" viewBox="0 0 20 20">
        <title>icon-coffee</title>
        <path fill="#000" d="M15,17H14V9h3a3,3,0,0,1,3,3h0A5,5,0,0,1,15,17Zm1-6v3.83A3,3,0,0,0,18,12a1,1,0,0,0-1-1Z"/>
        <rect fill="#000" x="1" y="7" width="15" height="12" rx="3" ry="3"/>
        <path fill="#000" d="M7.07,5.42a5.45,5.45,0,0,1,0-4.85,1,1,0,0,1,1.79.89,3.44,3.44,0,0,0,0,3.06,1,1,0,0,1-1.79.89Z"/>
        <path fill="#000" d="M3.07,5.42a5.45,5.45,0,0,1,0-4.85,1,1,0,0,1,1.79.89,3.44,3.44,0,0,0,0,3.06,1,1,0,1,1-1.79.89Z"/>
        <path fill="#000" d="M11.07,5.42a5.45,5.45,0,0,1,0-4.85,1,1,0,0,1,1.79.89,3.44,3.44,0,0,0,0,3.06,1,1,0,1,1-1.79.89Z"/>
    </symbol>
</svg>
XML 复制代码
<svg class="icon" aria-hidden="true">
    <use href="#icon-coffee" class="coffee-1" />
</svg>

<svg class="icon" aria-hidden="true">
    <use href="#icon-coffee" class="coffee-2" />
</svg>

<svg class="icon" aria-hidden="true">
    <use href="#icon-coffee" class="coffee-3" />
</svg>

我们使用 <use> 渲染了多个图标:

现在让我们尝试为每个图标实例更改填充颜色:

CSS 复制代码
.coffee-1 {
    fill: lime;
}

.coffee-2 {
    fill: skyblue;
}

.coffee-3 {
    fill: brown;
} 

图标的填充颜色仍然不会改变,因为 <use> 元素的后代元素(<rect><path>)上的 fill="#000" 正在覆盖继承的颜色值。

为了防止这种情况发生,我们需要强制 <rect><path> 元素继续颜色值:

CSS 复制代码
:is(rect, path) {
    svg & {
        fill: inherit;
    }
}

在我们这个示例,需要强制的是 <rect><path> ,换成别的图形,你可以还需要对其他元素做类似操作。你可以来点粗暴的方式,那就是将 svg 的所有后代元素的 fill 属性的值重置为 inherit

CSS 复制代码
svg * {
    fill: inherit;
}

现在,我们在每个 <use> 元素上设置的颜色被应用到了它的每个后代元素上。

通过种方式,你可以获得任意你想的颜色图标:

Demo 地址:codepen.io/airen/full/...

特别声明,CSS 的 inherit 是一个很有意思的特性,与其具有同等地位的还有 initialunsetrevert 。如果你对它们不怎么了解,那么强烈建议你移步阅读《现代 CSS》中的 《CSS 显式默认值:inherit,initial,unset 和 revert》!

CSS 的 currentColor 是个神器

如果仅仅是调整图标颜色,那么 currentColor 将是一把神器。

上面这种方案,能够强制样式属性从 <use> 样式中继承是很强大,但是如果你有一个具有多个元素的图标,并且你不希望所有这些元素都从 <use> 继续相同的填充颜色,那么你就需要考虑其他的解决方案。继续以上面的"咖啡"图标为例,假设你希望"咖啡杯"与"咖啡热气"的填充颜色不相同,怎么办?

针对于上图这种情景,我们可以使用 CSS 的 currentColor 变量来为 <use> 元素的内容设置样式。使用 CSS 的 currentColor 变量结合上述技术,我们可以在一个元素上指定两种不同的颜色,而不仅仅是一种。这种技术的背后思想是在 <use> 上同时使用 fillcolor 属性,然后利用 currentColor 的变量特性,使这些颜色继承到 <use> 的内容中。

利用这种技术,我们需要对 <symbol> 做一些调整。例如上面的"咖啡"图标为例,我在 <symbol> 中新增了两个 <g> 元素,它将"咖啡杯"和"烟"分成两个组,并且将 fill 属性移至 <g> 元素。

XML 复制代码
<svg xmlns="http://www.w3.org/2000/svg" class="sr-only">
    <symbol id="icon-coffee" viewBox="0 0 20 20">
        <title>icon-coffee</title>
        <g class="cup" fill="currentColor">
              <path d="M15,17H14V9h3a3,3,0,0,1,3,3h0A5,5,0,0,1,15,17Zm1-6v3.83A3,3,0,0,0,18,12a1,1,0,0,0-1-1Z"/>
              <rect  x="1" y="7" width="15" height="12" rx="3" ry="3"/>
        </g>
        <g class="smoke">
            <path  d="M7.07,5.42a5.45,5.45,0,0,1,0-4.85,1,1,0,0,1,1.79.89,3.44,3.44,0,0,0,0,3.06,1,1,0,0,1-1.79.89Z"/>
            <path  d="M3.07,5.42a5.45,5.45,0,0,1,0-4.85,1,1,0,0,1,1.79.89,3.44,3.44,0,0,0,0,3.06,1,1,0,1,1-1.79.89Z"/>
            <path  d="M11.07,5.42a5.45,5.45,0,0,1,0-4.85,1,1,0,0,1,1.79.89,3.44,3.44,0,0,0,0,3.06,1,1,0,1,1-1.79.89Z"/>
        </g>
    </symbol>
</svg>

注意,我在 .cup (咖啡杯)的 <g> 元素上设置了 fillcurrentColor ,同时将 .smoke 和其子元素的 fill 移除。如果我们继续以 inherit 来处理,事情反而会变得更为复杂一些。现在这样做,有一个很明显的优势,fillcurrentColor 的 SVG 元素,它将继承 <use> 元素的 color 值(咖啡杯),未设置 fill 的 SVG 元素,它将直接继承 <use> 元素的 fill 值(烟)。如果我们继续使用 inherit 关键词来强制继承 <use> 的值,那么两个 <g> 元素(.cup.smoke)都将继承相同的值,currentColor 将不再起作用。

现在,同时给 <use> 元素指定 fillcolor 属性值,我们就可以使"咖啡杯和其上面的烟"具有不同的颜色:

CSS 复制代码
.coffee-1 {
    fill: red;
    color: orange;
}

.coffee-2 {
    fill: pink;
    color: lime;
}

.coffee-3 {
    fill: yellow;
    color: #f26ace;
}

每个 <use> 元素都有自己的填充和颜色值。就这个示例来说,.cup 将会继承 <use> 元素的 color 属性的值,因为它的 fillcurrentColor (在<symbol> 中);.smoke 将会继承 <use> 元素的 fill 属性的值,因为它没有设置 fill 属性值(在<symbol> 中)。

你可以尝试在下面的示例中,随意调整 fillcolor 的颜色值,将会获得任意你喜欢的图标(双色):

Demo 地址:codepen.io/airen/full/...

注意,currentColor 也适用于单色图标,这比使用 inherit 还要更简便,唯一的要求是,需要在 <symbol> 中将 fill 属性的值设置为 currentColor 。你可以通过 <g> 元素,避免在每个元素上重置 fill 属性的值为 currentColor

XML 复制代码
<svg xmlns="http://www.w3.org/2000/svg" class="sr-only">
    <symbol id="icon-coffee" viewBox="0 0 20 20">
        <title>icon-coffee</title>
        <g fill="currentColor">
            <path d="M15,17H14V9h3a3,3,0,0,1,3,3h0A5,5,0,0,1,15,17Zm1-6v3.83A3,3,0,0,0,18,12a1,1,0,0,0-1-1Z" />
            <rect x="1" y="7" width="15" height="12" rx="3" ry="3" />
            <path d="M7.07,5.42a5.45,5.45,0,0,1,0-4.85,1,1,0,0,1,1.79.89,3.44,3.44,0,0,0,0,3.06,1,1,0,0,1-1.79.89Z" />
            <path d="M3.07,5.42a5.45,5.45,0,0,1,0-4.85,1,1,0,0,1,1.79.89,3.44,3.44,0,0,0,0,3.06,1,1,0,1,1-1.79.89Z" />
            <path d="M11.07,5.42a5.45,5.45,0,0,1,0-4.85,1,1,0,0,1,1.79.89,3.44,3.44,0,0,0,0,3.06,1,1,0,1,1-1.79.89Z" />
        </g>
    </symbol>
</svg> 

<svg class="icon-coffee" aria-hidden="true">
    <use href="#icon-coffee" class="coffee" />
</svg>
CSS 复制代码
.coffee {
    color: lime;
}

Demo 地址:codepen.io/airen/full/...

王者归来:不要忘了 NB 的 CSS 自定义属性

继续加码,如果图标不是单色,也不仅是双色,而是更多的色彩呢?

现在我们需要更多的变量。这也意味着,仅使用 currentColor 这个单一变量已经无法满足超出双色的情景了。庆幸的是,我们可以借助现代 CSS 中的自定义属性,即 CSS 变量来设置更多的变量。

使用 CSS 变量来样式化 <use> 内容与使用 currentColor 类似,首先我们需要将 <symbol> 中每个元素的 fill 属性值设置为 CSS 自定义属性:

XML 复制代码
<svg xmlns="http://www.w3.org/2000/svg" class="sr-only">
    <symbol id="icon-coffee" viewBox="0 0 20 20">
        <title>icon-coffee</title>
        <path fill="var(--fill-1, lime)" d="M15,17H14V9h3a3,3,0,0,1,3,3h0A5,5,0,0,1,15,17Zm1-6v3.83A3,3,0,0,0,18,12a1,1,0,0,0-1-1Z" />
        <rect fill="var(--fill-2, lime)" x="1" y="7" width="15" height="12" rx="3" ry="3" />
        <path fill="var(--fill-3, lime)" d="M7.07,5.42a5.45,5.45,0,0,1,0-4.85,1,1,0,0,1,1.79.89,3.44,3.44,0,0,0,0,3.06,1,1,0,0,1-1.79.89Z" />
        <path fill="var(--fill-4, lime)" d="M3.07,5.42a5.45,5.45,0,0,1,0-4.85,1,1,0,0,1,1.79.89,3.44,3.44,0,0,0,0,3.06,1,1,0,1,1-1.79.89Z" />
        <path fill="var(--fill-5, lime)" d="M11.07,5.42a5.45,5.45,0,0,1,0-4.85,1,1,0,0,1,1.79.89,3.44,3.44,0,0,0,0,3.06,1,1,0,1,1-1.79.89Z" />
    </symbol>
</svg>

<svg class="icon-coffee" aria-hidden="true">
    <use href="#icon-coffee" class="coffee" />
</svg>  

上面的代码中,我们为每个元素都设置了一个 CSS 自定义属性,并且提供了一个备用值 lime 。当你没有给每个变时显式指定值时,都将会使用备用值 lime 作为每个自定义属性的值。因此,你看到的咖啡杯将是一个纯色(lime)。

基于这个前提,你可以在 <use> 中为 CSS 自定义属性指定值:

CSS 复制代码
.coffee {
    --fill-1: red;
    --fill-2: green;
    --fill-3: blue;
    --fill-4: orange;
    --fill-5: pink;
}

这样你就可以非常容易得到一个多色有图标:

Demo 地址:codepen.io/airen/full/...

通过利用CSS 层叠,尽管在 Shadow DOM中,对 <use> 元素的内容进行样式化可以变得不那么复杂。而且借助CSS 自定义属性(无论是仅使用 currentColor 还是自定义属性),我们可以穿透 Shadow DOM的边界,按照我们的喜好定制图形,同时为任何出现问题时提供非常好的回退机制。

就我个人而言,我对 CSS 自定义属性与 SVG 结合的功能非常兴奋。我喜欢它们在一起时的强大功能,特别是考虑到我们拥有的出色回退机制。但需要知道的是,CSS 自定义属性非常的强大,它可以帮助以更轻便的方式做更多复杂的事情,但它也有很多细节需要注意。不过,这部分内容已超出这节课的范畴,如果你感兴趣的话,可以移步阅读《CSS 自定义属性你知道多少》。

写在最后

最后以两个真实的案例来结束今天的分享。首先分享 @Jakob Eriksen 在 CodePen 提供的案例:

Demo 地址:codepen.io/jakob-e/ful...

再来一个爆炸的魔方:

Demo 地址:codepen.io/airen/full/...

特别声明:如果你对 SVG 和 CSS 更多技巧感兴趣,请关注我的第五本小册《深入浅出 SVG:你需要知道的关于 SVG 的一切》。温馨提示,提前预定可享受五折优惠,如果您有这个意向,请发邮件到 airenliao@gmail.com ,或在下面评论中留言。


如果你觉得该教程对你有所帮助,请给我点个赞。要是你喜欢 CSS ,或者想进一步了解和掌握 CSS 相关的知识,请关注我的专栏,或者移步阅读下面这些系列教程:

相关推荐
科技探秘人11 分钟前
Chrome与火狐哪个浏览器的隐私追踪功能更好
前端·chrome
科技探秘人12 分钟前
Chrome与傲游浏览器性能与功能的深度对比
前端·chrome
JerryXZR17 分钟前
前端开发中ES6的技术细节二
前端·javascript·es6
七星静香19 分钟前
laravel chunkById 分块查询 使用时的问题
java·前端·laravel
q24985969322 分钟前
前端预览word、excel、ppt
前端·word·excel
小华同学ai27 分钟前
wflow-web:开源啦 ,高仿钉钉、飞书、企业微信的审批流程设计器,轻松打造属于你的工作流设计器
前端·钉钉·飞书
Gavin_91536 分钟前
【JavaScript】模块化开发
前端·javascript·vue.js
懒大王爱吃狼2 小时前
Python教程:python枚举类定义和使用
开发语言·前端·javascript·python·python基础·python编程·python书籍
逐·風6 小时前
unity关于自定义渲染、内存管理、性能调优、复杂物理模拟、并行计算以及插件开发
前端·unity·c#
Devil枫6 小时前
Vue 3 单元测试与E2E测试
前端·vue.js·单元测试