如何在 React 中导入 SVG 图标
How to Import SVG icons in React
我想在应用程序中导入太多 SVG 图标,并且每个图标都需要通过 css 自定义颜色,哪种导入方式最简单?
导入到 <img/>
标签将不支持通过 css 填充更改颜色。
为每个图标创建一个 .js 组件对于 250 多个图标来说太难了。
另一个选择是什么?请帮忙
import IconArrow from "./Arrow.svg";
import Circlearrowdownright from "./Arrow.js";
<img className="ico" src={IconArrow} />
<i className="ico"><Circlearrowdownright /></i>
您可以动态导入 SVG 并即时渲染 (CodeSandbox)。无需为每个 SVG 文件创建单独的 .js
组件。
hook
function useDynamicSVGImport(name, options = {}) {
const ImportedIconRef = useRef();
const [loading, setLoading] = useState(false);
const [error, setError] = useState();
const { onCompleted, onError } = options;
useEffect(() => {
setLoading(true);
const importIcon = async () => {
try {
ImportedIconRef.current = (
await import(`./${name}.svg`)
).ReactComponent;
if (onCompleted) {
onCompleted(name, ImportedIconRef.current);
}
} catch (err) {
if (onError) {
onError(err);
}
setError(err);
} finally {
setLoading(false);
}
};
importIcon();
}, [name, onCompleted, onError]);
return { error, loading, SvgIcon: ImportedIconRef.current };
}
Icon
使用钩子的组件
/**
* Simple wrapper for dynamic SVG import hook. You can implement your own wrapper,
* or even use the hook directly in your components.
*/
export const Icon = ({ name, onCompleted, onError, ...rest }) => {
const { error, loading, SvgIcon } = useDynamicSVGImport(name, {
onCompleted,
onError
});
if (error) {
return error.message;
}
if (loading) {
return "Loading...";
}
if (SvgIcon) {
return <SvgIcon {...rest} />;
}
return null;
};
用法
return (
<>
<Icon
name="Arrow"
fill="gray"
width="100"
onCompleted={handleOnCompleted}
onError={handleIconError}
/>
<Icon
name="delete"
fill="gray"
width="50"
onCompleted={handleOnCompleted}
onError={handleIconError}
/>
</>
);
React 与本机 Web 组件配合得很好。只有当您想使用事件与它们交互或传递数据时,React(仍然)无法支持标准:https://custom-elements-everywhere.com/
- 创建一个
<svg-icon>
标签仅需几行代码。
- 添加了
replaceWith
属性,因此您加载的 <svg>
会替换 <svg-icon>
,从而更易于使用全局 CSS.
- 添加了一个
shadowRoot
属性 将任何内容 移动到 shadowDOM
customElements.define("svg-icon", class extends HTMLElement {
async connectedCallback(
src = this.getAttribute("src"),
shadowRoot = this.shadowRoot || this.attachShadow({mode:"open"})
) {
shadowRoot.innerHTML = await (await fetch(src)).text()
shadowRoot.append(...this.querySelectorAll("[shadowRoot]"))
this.hasAttribute("replaceWith") && this.replaceWith(...shadowRoot.childNodes)
}
});
body {
display: grid;
grid: 1fr/1fr 5fr;
}
path {
stroke: green;
stroke-width: .2;
fill: red;
}
<svg-icon replaceWith src="https://svg-cdn.github.io/bi-arrows.svg"></svg-icon>
<svg-icon src="https://svg-cdn.github.io/simple-worldmap.svg">
<style shadowRoot>
path {
fill: orange
}
</style>
</svg-icon>
您可以直接将其作为 React 组件导入使用:
import { ReactComponent as ExampleIcon} from './icons/ExampleIcon.svg';
<ExampleIcon className="css-class"/>
我想在应用程序中导入太多 SVG 图标,并且每个图标都需要通过 css 自定义颜色,哪种导入方式最简单?
导入到 <img/>
标签将不支持通过 css 填充更改颜色。
为每个图标创建一个 .js 组件对于 250 多个图标来说太难了。
另一个选择是什么?请帮忙
import IconArrow from "./Arrow.svg";
import Circlearrowdownright from "./Arrow.js";
<img className="ico" src={IconArrow} />
<i className="ico"><Circlearrowdownright /></i>
您可以动态导入 SVG 并即时渲染 (CodeSandbox)。无需为每个 SVG 文件创建单独的 .js
组件。
hook
function useDynamicSVGImport(name, options = {}) {
const ImportedIconRef = useRef();
const [loading, setLoading] = useState(false);
const [error, setError] = useState();
const { onCompleted, onError } = options;
useEffect(() => {
setLoading(true);
const importIcon = async () => {
try {
ImportedIconRef.current = (
await import(`./${name}.svg`)
).ReactComponent;
if (onCompleted) {
onCompleted(name, ImportedIconRef.current);
}
} catch (err) {
if (onError) {
onError(err);
}
setError(err);
} finally {
setLoading(false);
}
};
importIcon();
}, [name, onCompleted, onError]);
return { error, loading, SvgIcon: ImportedIconRef.current };
}
Icon
使用钩子的组件
/**
* Simple wrapper for dynamic SVG import hook. You can implement your own wrapper,
* or even use the hook directly in your components.
*/
export const Icon = ({ name, onCompleted, onError, ...rest }) => {
const { error, loading, SvgIcon } = useDynamicSVGImport(name, {
onCompleted,
onError
});
if (error) {
return error.message;
}
if (loading) {
return "Loading...";
}
if (SvgIcon) {
return <SvgIcon {...rest} />;
}
return null;
};
用法
return (
<>
<Icon
name="Arrow"
fill="gray"
width="100"
onCompleted={handleOnCompleted}
onError={handleIconError}
/>
<Icon
name="delete"
fill="gray"
width="50"
onCompleted={handleOnCompleted}
onError={handleIconError}
/>
</>
);
React 与本机 Web 组件配合得很好。只有当您想使用事件与它们交互或传递数据时,React(仍然)无法支持标准:https://custom-elements-everywhere.com/
- 创建一个
<svg-icon>
标签仅需几行代码。 - 添加了
replaceWith
属性,因此您加载的<svg>
会替换<svg-icon>
,从而更易于使用全局 CSS. - 添加了一个
shadowRoot
属性 将任何内容 移动到 shadowDOM
customElements.define("svg-icon", class extends HTMLElement {
async connectedCallback(
src = this.getAttribute("src"),
shadowRoot = this.shadowRoot || this.attachShadow({mode:"open"})
) {
shadowRoot.innerHTML = await (await fetch(src)).text()
shadowRoot.append(...this.querySelectorAll("[shadowRoot]"))
this.hasAttribute("replaceWith") && this.replaceWith(...shadowRoot.childNodes)
}
});
body {
display: grid;
grid: 1fr/1fr 5fr;
}
path {
stroke: green;
stroke-width: .2;
fill: red;
}
<svg-icon replaceWith src="https://svg-cdn.github.io/bi-arrows.svg"></svg-icon>
<svg-icon src="https://svg-cdn.github.io/simple-worldmap.svg">
<style shadowRoot>
path {
fill: orange
}
</style>
</svg-icon>
您可以直接将其作为 React 组件导入使用:
import { ReactComponent as ExampleIcon} from './icons/ExampleIcon.svg';
<ExampleIcon className="css-class"/>