【问题标题】:Best way to import SVG icons into a Svelte app将 SVG 图标导入 Svelte 应用程序的最佳方式
【发布时间】:2021-05-10 04:06:48
【问题描述】:

我将大约 80 个自定义 SVG 图标导入到 Svelte 前端应用程序中。它以 https://github.com/sveltejs/template 为基础,使用 Rollup 构建,包括 Typescript、Tailwind 和所有现代好东西。

难题是如何将图标添加到应用程序中。作为 SVG,图标是不超过 2kB 的短 XML 文本字符串。

选项 1:作为图片资源

  1. 将所有图标以foo.svg 上传到public/assets/icons
  2. 创建一个精简组件<Icon type="foo' />,使用<img src="foo.svg> 显示图标。

这种方法意味着图标不是代码的一部分。

优点:图标可以由前端代码按需动态加载。无需将所有图标捆绑到应用代码中。

缺点:如果有很多新图标,页面加载速度会很慢,并且浏览器必须获取十几个 1kB 的文件。将应用部署为 PWA 意味着我们需要手动告诉它预先缓存图标。

选项 2:作为应用构建的一部分

  1. 使用https://github.com/cristovao-trevisan/svelte-iconhttps://github.com/codefeathers/rollup-plugin-svelte-svg之类的东西直接将每个图标导入代码:import Home from './icons/home.svg';
  2. 创建一个纤细的组件,选择正确的导入组件或 SVG 字符串并显示它。

在这里,图标作为文本字符串与应用程序本身捆绑在一起。

优点:图标作为应用程序包的一部分提供。缓存是不必要的。可以动态修改一些图标代码,例如加载时的颜色、viewBox 等。

缺点:没有必要在应用程序中包含所有图标以减少第一个字节的时间。不能在不增加复杂性的情况下进行捆绑拆分等。使渲染速度变慢,因为 Javascript 代码需要首先将字符串转换为 SVG,而不仅仅是加载图像。

问题

  • 从这个分析看来,在应用程序中构建图标是一种更好的方法,但我是否遗漏了什么?
  • 如果“图标”是 50-100kB 的详细图像而不是此处的小字符串,那么微积分是否会改变?

【问题讨论】:

  • 选项 3:使用仅包含 d 路径数据的字符串创建带有 <svg-icon> 自定义元素的 SVG 客户端;请参阅iconmeister.github.io - 我从未做过 Svelte 版本,因为 Svelte 可以很好地处理 <svg-icon> 本机元素。我已经从不同的 IconSet 转换了 7000 多个图标 - JS 代码只有 800 字节 GZipped
  • 附言。如果 "icons"50-100kB,则 "designer" 有问题。我在 16kB300+ Country flags29kB 中做了 52 Playingcards
  • 我总是将它们内联(选项 2),但请确保优化所有 svg,这些尺寸确实非常大,您可以使用 svgomg 之类的工具进行优化。如果图标来自设计师,他们的工具也可以导出它们,只需检查 svg,如果您看到很多废话而不是普通路径,则表明它们未优化。
  • 专注于移动 3G,速度必须先行(我更喜欢 Danny 的选项 3,就像其他人说的大小对于 svg 来说似乎很大)
  • @StephaneVanraes 你是说 1kb 大还是 50kb 大?

标签: javascript typescript svg svelte rollupjs


【解决方案1】:

以下方法具有以下优点:

  • 为您的应用维护所有图标的中心点
  • 减少了获取 SVG 图标的网络请求
  • 整个应用程序中可重复使用的图标,没有重复的 svg 元素

有一个像这样的专用 Icon.svelte 组件设置:

<script>
    export let name;
    export let width = "1rem";
    export let height = "1rem";
    export let focusable = false;
    let icons = [
        {
          box: 24,
          name: "save",
          svg: `<g stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"/><path d="M17 21v-8H7v8"/><path d="M7 3v5h8"/></g>`
        },
        {
          box: 32,
          name: "trash",
          svg: `<path d="M12 12h2v12h-2z" /><path d="M18 12h2v12h-2z" /><path d="M4 6v2h2v20a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V8h2V6zm4 22V8h16v20z" /><path d="M12 2h8v2h-8z" />`
        }
    ];
    let displayIcon = icons.find((e) => e.name === name);
</script>
<svg
  class={$$props.class}
  {focusable}
  {width}
  {height}
  viewBox="0 0 {displayIcon.box} {displayIcon.box}">{@html displayIcon.svg}</svg>

然后你可以像这样使用它:

<Icon name="trash" class="this-is-optional" />

【讨论】:

  • 在 typescript 中使用 this 当前会为 "name" 属性抛出 typeerror,因为当使用 react/tsx 和 svelte 转换为 tsx 用于 typescript 时,这似乎是保留的。还会为可聚焦属性引发类型错误,但似乎可以将其更改为“false”作为包含 false 而不是布尔类型的字符串。
  • 这是一个很好的解决方案!我想知道,如果可能的话,我如何自动获取父元素的字体大小,而不是作为道具传入宽度高度?这甚至可能吗?不管真棒解决方案!
  • 可以使用带有图标名称的对象作为键来代替数组,这样您就不必在每次呈现图标时都执行find
  • 您可以通过 preserveAspectRatioviewBox 属性使 SVG 图像具有响应性:developer.mozilla.org/en-US/docs/Web/SVG/Attribute/… 关于缩放 SVG 图像所需了解的一切:css-tricks.com/scale-svg
【解决方案2】:

您只需将文件扩展名更改为 .svelte 并将 SVG 作为普通组件导入即可。

【讨论】:

  • 它增加了在文件中添加
【解决方案3】:

另一种方法是在公共文件夹中使用符号 defs 文件(例如:icons.svg)。 然后在你的代码中做这样的事情:

图标.svelte

<script>
    export let name;
    export let width = "1.5rem";
    export let height = "1.5rem";
    export let focusable = false;
</script>

<svg class={$$props.class} {focusable} {width} {height}>
    <use href={`/icons.svg#${name}`} />
</svg>

icons.svg

<svg aria-hidden="true" style="position: absolute; width: 0; height: 0; overflow: hidden;" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    <defs>
        <symbol id="icon-warning" viewBox="0 0 20 20">
            <path d="M19.511 17.98l-8.907-16.632c-0.124-0.215-0.354-0.348-0.604-0.348s-0.481 0.133-0.604 0.348l-8.906 16.632c-0.121 0.211-0.119 0.471 0.005 0.68 0.125 0.211 0.352 0.34 0.598 0.34h17.814c0.245 0 0.474-0.129 0.598-0.34 0.124-0.209 0.126-0.469 0.006-0.68zM11 17h-2v-2h2v2zM11 13.5h-2v-6.5h2v6.5z">
            </path>
        </symbol>
    </defs>
</svg>

App.svelte

<Icon name="icon-warning" />

这样您就可以使用一个 http 调用来加载 svg 文件。然后只需在标记中使用您需要的部分。

【讨论】:

  • 虽然我喜欢这种方法,因为它非常直接地使用 HTML,但我无法让它始终如一地工作。有时使用 use 引用定位 id 会起作用,有时它会使用整个 &lt;path&gt; 作为 id。
【解决方案4】:

一个可行的解决方案是将 SVG 保存在单独的 IconService.js 中:

export const chevron_down = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"feather feather-chevron-down\"><polyline points=\"6 9 12 15 18 9\"></polyline></svg>";

export const chevron_right = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"feather feather-chevron-right\"><polyline points=\"9 18 15 12 9 6\"></polyline></svg>";

这可以很容易地在 svelte @html 函数中导入和使用。

<script>
    import {chevron_down, chevron_right} from 'IconService';
</script>

{@html chevron_down}

【讨论】:

  • 这到底有什么帮助?
  • 认为问题是:将 SVG 图标导入 Svelte 应用程序的最佳方法
【解决方案5】:

使用类似 {@html SVG_CODE} 从另一个组件或变量呈现 svg 代码是一个糟糕的选择。这会带来 XSS 和其他攻击的风险。 检查:https://github.com/sveltejs/svelte/issues/2545

我认为使用像 rollup-plugin-svelte-svg(https://www.npmjs.com/package/rollup-plugin-svelte-svg) 这样的插件会是更好的选择

1.使用npm安装

npm i -D rollup-plugin-svelte-svg

2.在汇总配置中,只需在 svelte 之前调用 svelteSVG。


export default {
    
    plugins: [
        svelteSVG({
            // optional SVGO options
            // pass empty object to enable defaults
            svgo: {}
        }),
    ],
    ...
}

3.然后你就可以在你的JS中导入svg了:

<script>
    import Logo from "./logo.svg";
</script>

<Logo width=20 />

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-11-30
    • 2011-06-06
    • 1970-01-01
    • 2014-12-18
    • 1970-01-01
    • 2019-11-30
    • 2015-01-13
    相关资源
    最近更新 更多