如何将整个SVG图像文件夹(或如何动态加载它们)导入React Web App?

Wis*_*Man 15 javascript import svg dynamic reactjs

我有一个组件,它接受:itemName并吐出一个包含图像的html包.每个图像的图像都不同.

这就是我所拥有的:

import React, { Component } from 'react';
import { NavLink } from 'react-router-dom';

import SVGInline from "react-svg-inline";

export default (props) => (
  <NavLink className="hex" activeClassName="active" to={'/hex/' + props.itemName}> {React.createElement(SVGInline, {svg: props.itemName})} </NavLink>
)
Run Code Online (Sandbox Code Playgroud)

我怎么能让这个组件工作?

我知道,如果我只是明确地导入了我的所有图像,我可以像这样调用我的图像......

import SVGInline from "react-svg-inline";
import SASSSVG from "./images/sass.svg";

<NavLink className="hex" activeClassName="active" to="/hex/sass"><SVGInline svg={ SASSSVG } /></NavLink>
Run Code Online (Sandbox Code Playgroud)

这可行,但由于我需要包含~60 svgs,它会增加大量的多余代码.

另外,我在这个问题中找到这段代码......

import * as IconID from './icons';
Run Code Online (Sandbox Code Playgroud)

但这似乎不起作用(这是问题的一部分,而不是答案),而答案对于回答我提出的问题来说有点过于特殊.

我也发现了这个问题,但是又有一个答案(虽然未经批准),它有更多的问题而不是答案.因此,在安装react-svg后,我设置了一个测试,看看答案是否正常工作......

import React, { Component } from 'react';
import ReactDOM from 'react-dom'
import { NavLink } from 'react-router-dom';
import ReactSVG from 'react-svg'

export default (props) => (
  <NavLink className="hex" activeClassName="active" to={'/hex/' + props.itemName}>
    <ReactSVG
      path={"images/" + props.itemName + ".svg"}
      callback={svg => console.log(svg)}
      className="example"
    />
  </NavLink>
)
Run Code Online (Sandbox Code Playgroud)

但是,正如该问题的OP所要求的那样,即使将我的整个图像文件夹复制到我的构建文件夹中,该页面也找不到我的svg.我也试过"./images/"

我觉得我只是错过了最后一条关键信息,在寻找过去的一天之后,我希望有人能找出我失踪的那条.

sky*_*ize 12

如果使用React,我强烈怀疑你也在使用Webpack.您可以使用require.context而不是es6 import,Webpack将在构建时为您解决它.

require.context ( folder, recurse, pattern )
Run Code Online (Sandbox Code Playgroud)
  • folder - String - 开始扫描文件的文件夹的路径.
  • recurse - Boolean - 是否递归扫描文件夹.
  • pattern - RegExp - 描述要包含哪些文件的匹配模式.

每个例子的第一行......

const reqSvgs = require.context ( './images', true, /\.svg$/ )
Run Code Online (Sandbox Code Playgroud)

...创建Require Context将*.svg文件images夹中的所有文件路径映射到导入.这为我们提供了一个reqSvgs以一些附加属性命名的专门需求函数.

其中一个属性reqSvgskeys方法,它返回所有有效文件路径的列表.

const allSvgFilepaths = reqSvgs.keys ()
Run Code Online (Sandbox Code Playgroud)

我们可以传递其中一个文件路径reqSvgs以获取导入的图像.

const imagePath = allSvgFilePaths[0]
const image = reqSvgs ( imagePath )
Run Code Online (Sandbox Code Playgroud)

这个api对于这个用例是有约束力和不直观的,所以我建议将集合转换为更常见的JavaScript数据结构,以便更容易使用.

每个图像都将在转换过程中导入.小心,因为这可能是一个脚枪.但它提供了一种相当简单的机制,可以将多个文件复制到构建文件夹,而这些文件可能永远不会被其他源代码显式引用.

以下是3个可能有用的示例转换.


排列

创建导入文件的数组.

const reqSvgs = require.context ( './images', true, /\.svg$/ )
const paths = reqSvgs.keys ()

const svgs = paths.map( path => reqSvgs ( path ) )
Run Code Online (Sandbox Code Playgroud)

对象数组

创建一个对象数组,每个对象{ path, file }用于一个图像.

const reqSvgs = require.context ( './images', true, /\.svg$/ )

const svgs = reqSvgs
  .keys ()
  .map ( path => { path, file: svg ( path ) } )
Run Code Online (Sandbox Code Playgroud)

普通对象

创建一个对象,其中每个路径都是其匹配文件的键.

const reqSvgs = require.context ('./images', true, /\.svg$/ )

const svgs = reqSvgs
  .keys ()
  .reduce ( ( images, path ) => {
    images[path] = reqSvgs ( path )
    return images
  }, {} )
Run Code Online (Sandbox Code Playgroud)

SurviveJS给出了一个更广义的例子require.context在这里 SurviveJS的WebPack动态加载.


小智 9

偶然发现了这个问题 - 我最初有“接受的答案”,但我对每个 svg 造成了 http 请求,这触发了速率限制。所以我最终得到了接受的答案和@karthik 建议的组合 - 在 request.context 中使用加载器

从 CRA 2.0 开始,包含 @svgr 以将 svg 作为反应组件导入。

const reqSvgs = require.context('!@svgr/webpack!flag-icon-css/flags/4x3', true, /\.svg$/)
Run Code Online (Sandbox Code Playgroud)

所以这里我们结合了一个 svg loader 和 require.context

const flagMap = reqSvgs.keys().reduce((images, path) => {
  const key = path.substring(path.lastIndexOf('/') + 1, path.lastIndexOf('.'))
  images[key] = reqSvgs(path).default
  return images
}, {})
Run Code Online (Sandbox Code Playgroud)

然后我们将所有这些映射到一个 json 对象中,以便我们可以使用键查找

在 jsx 中渲染 svg:

const Flag = flagMap['dk']
return (
  <Flag />
)
Run Code Online (Sandbox Code Playgroud)

快乐的日子,svgs 包含在 bundle 中,没有单独的 http 请求

  • 我尝试过这个,但它不起作用。flagMap 包含 svg 的静态路径,但不能这样渲染。这是错误:[mobx]遇到由反应或观察者组件抛出的未捕获的异常,在:'Reaction[observer]'DOMException:无法在'Document'上执行'createElement':提供的标签名称('/ static/media/wine.61384ebe.svg') 不是有效名称。 (2认同)

quo*_*Bro 5

您可以使用单个 SVG 精灵,而不是多个 SVG 文件。

可以使用svg-sprite-generator从 SVG 文件目录生成 SVG sprite :

svg-sprite-generate -d images -o images/sprite.svg
Run Code Online (Sandbox Code Playgroud)

然后像这样使用它:

import React from 'react';
import { NavLink } from 'react-router-dom';
import sprite from './images/sprite.svg';

export default (props) => (
  <NavLink className="hex" activeClassName="active" to={'/hex/' + props.itemName}>
    <svg xmlns="http://www.w3.org/2000/svg" width="30" height="30">
      <use xlinkHref={`${sprite}#${props.itemName}`} />
    </svg>
  </NavLink>
)
Run Code Online (Sandbox Code Playgroud)