svg 색상 부분 처리
예상되는 사용법은 다음과 같습니다.
<Icon name="account" color="red" size={
[50,50]}/>
或者 size={
50} 这样的写法
따라서 세 가지 매개변수가 필요합니다.
- 이름
- 색상
- 크기
이전 문서의 단계를 수행한 후 이름 요구 사항이 실현되었음을 확인할 수 있습니다.
크기 구현은 비교적 간단하므로 너무 자세히 설명하지 않고(크기 처리 프로세스는 다음 코드에도 반영됨) svg에 속성을 직접 추가하기만 하면 됩니다. 간단한 예를 들어 보겠습니다.
return (
<svg
width={
200} // 把这里换成变量就可以了,或者将样式统一放在一个对象里,然后用展开符也行
height={
200}
aria-hidden="true"
>
<use xlinkHref={
iconName} />
</svg>
)
색상 처리와 관련하여 두 가지 요구 사항이 있습니다:
하나는 원본 svg와 함께 제공되는 색상을 직접 제거하고 모든 색상은 사용자가 재설정(또는 기본 색상을 가짐)하는 것입니다
. 색상의 속성을 전달했습니다. 사용할 때 사용자 정의 색상만 사용하고, 그렇지 않으면 원래 svg 색상을 유지합니다.(이것도 제 요구 사항입니다)
이 두 가지 요구 사항의 경우 처리 방식이 다릅니다(svg-sprite-loader를 사용하는 경우에만). 첫 번째 요구 사항은 구현하기가 비교적 간단하고 두 번째 요구 사항은 더 번거로운 것으로 아래에서 별도로 설명합니다 (어떤 경우에는 연습이 없으므로 아이디어 나 참조 만 제공합니다).
(1) 원본 svg 색상 제거
몇 가지 아이디어가 있습니다:
1. 원본 svg 이미지에서 채우기의 색상 값을 직접 제거합니다
2. 원래 색상을 덮어쓰도록 css를 통해 currentColor를 설정합니다.
원래 채우기의 색상 값을 직접 제거
일부 플러그인(예: svgo-loader)을 사용하거나 일부 스크립트를 직접 작성할 수 있습니다.
svgo-loader 설치
GitHub:svgo-loader
SVGO는 SVG-as-XML 데이터를 SVG-as-JS AST 표현으로 변환합니다. 그런 다음 모든 AST 데이터 항목에서 실행되고 일부 작업을 수행하며 마지막으로 SVGO는 AST를 SVG-as-XML 데이터 문자열로 다시 변환합니다.
SVGO는 플러그인이 많은 svg 옵티마이저입니다. SVG 요소를 제거 및 수정하고 콘텐츠를 접고 속성을 이동하는 등의 작업을 수행할 수 있습니다. -------- "svg-sprite-loader를 사용하여 아이콘 최적화"
에서 발췌
가장 중요한 것은 구성 파일에 webpack.config.js
자동 제거를 추가하는 것 입니다 fill
. 특정 코드는 다음과 같습니다( Nuggets 작성자 moonwanger 제공 ).
{
test: /\.svg$/,
use: [
{
loader: 'svg-sprite-loader', options: {
} },
{
loader: 'svgo-loader', options: {
plugins:[
// 加载时删除svg默认fill填充色
{
removeAttrs:{
attrs: 'fill'}}
]
}}
]
},
CSS를 통해 currentColor 설정
새 스타일 파일(예: icon.less)을 만들고 다음 css를 작성한 다음 이 스타일 파일을 이전에 작성된 일반 구성 요소 icon.js로 가져오십시오. icon.js에서 color
속성을 svg 태그에 추가하기만 하면 됩니다.
g[fill] {
fill: currentColor;
fill-opacity: 1;
}
g[stroke] {
stroke: currentColor;
stroke-opacity: 1;
}
path[fill] {
fill: currentColor;
fill-opacity: 1;
}
path[stroke] {
stroke: currentColor;
stroke-opacity: 1;
}
원리는 매우 간단합니다.본질적으로 svg 파일에서 g
태그나 태그 path
의 속성을 변경하여 색상을 제어하는 것입니다.
(2) 원본 svg 색상 유지
몇 가지 아이디어가 있습니다:
1. 웹 사이트의 다른 테마를 전환하는 구현과 유사하게 다른 css 파일을 동적으로 도입합니다(하지만 저는 이 작업에서 성공하지 못했습니다) 2.
js 선택기를 사용하여 id에 따라 해당 태그를 선택합니다. , 사용자가 색상 추가 스타일을 라벨에 전달할 때 when 속성;
두 번째 방법은 제가 여러 방법을 시도하다가 결국 채택했다가 실패한 방법인데 아이디어는 매우 간단합니다. . ; 심볼 태그의 자식은 svg 이미지의 경로이며 fill
속성은 태그의 색상을 제어합니다. 이러한 방식으로 를 사용하여 document.getElementById()
이 symbol
태그를 선택한 다음 를 사용하여 children
하위 요소를 가져온 다음 fill
경로의 속성을 제어할 수 있습니다. 이와 같이 사용자가 색상을 전달하지 않을 때,
내 프로젝트의 디렉토리 구조는 다음과 같습니다.
- icons
- svg 这个文件夹用来放所有的svg图片
- src
- app.js
Icons.js:
import React, {
useMemo, useState, useEffect } from 'react'
const Icon = ({
name,size,color}) => {
console.log(name,size,color)
const [svgModule, setSvgModule] = useState();
const [svgSize, setSvgSize] = useState({
width: 30,
height:30
});
// 允许自定义颜色
const setColor = () => {
let elem = document.getElementById(`${
name}`)
if(elem) {
let children = document.getElementById(`${
name}`).children
for(let i=0;i<children.length;i++) {
// foreach报错
children[i].style = `fill: ${
color}`; // 这里不能用with语句,严格模式不支持with
}
}
}
// 允许自定义尺寸
const setSize = () => {
if(!size){
setSvgSize({
width:30,height:30})
return
}
typeof size === "number" || "string" ?
setSvgSize({
width:size,height:size}) :
(size.length && size.length === 1 ?
setSvgSize({
width:size[0],height:size[0]}):
setSvgSize({
width:size[0],height:size[1]})
)
}
// 根据name拿到svg路径
const getSvg = async () => {
console.log("getSvg")
const svg = await import(`../../icons/svg/${
name}.svg`)
setSvgModule(svg)
}
const iconName = useMemo(() => {
setColor() // 保证页面刷新时不会因为找不到id为name的标签而报错
if (svgModule && svgModule.default) {
return `#${
svgModule.default.id}`
}
}, [svgModule])
useMemo(() => {
setSize()
}, [size])
useMemo( ()=>{
setColor()
},[color])
useEffect(() => {
getSvg()
}, [])
return (
<svg
{
...svgSize}
aria-hidden="true"
>
<use xlinkHref={
iconName} />
</svg>
)
}
export default Icon
(app.js)를 사용할 때 색상을 전달하는 효과:
import React from 'react';
import Icon from "./components/icons"
function App() {
return (
<div>
<p>test2</p>
<Icon name="account" size="200" color="pink"/>
<Icon name="pwd" color="green"/>
</div>
);
}
export default App;
색상을 전달하지 않는 효과:
<div>
<p>test2</p>
<Icon name="account" size="200"/>
<Icon name="pwd"/>
</div>
적응
테스트에 사용한 svg 이미지는 기본적으로 iconfont에서 다운받았고, 구조가 비교적 균일합니다.
하지만 가끔 프로젝트에서 디자이너가 제공하는 일부 svg 이미지는 더 많은 레이어와 태그가 있고(예를 들어 rect 및 g와 같은 여러 태그가 있음) 색상 속성은 어떤 태그의 채우기가 있는지 확실하지 않습니다. 매우 svg는 위와 같이 변경할 수 없습니다. 그림의 색상이므로 각 레이블을 순회하는 것이 가장 좋으므로 각 레이어가 순회되도록 다음 처리가 수행됩니다.
const setChildColor = (elem) => {
const {
children} = elem
if(children) {
for(let i=0;i<children.length;i++) {
children[i].style = `fill:${
color}`
if(children[i].children) {
setChildColor(children[i])
}
}
}
}
// 允许自定义颜色
const setColor = () => {
let elem = document.getElementById(`${
name}`)
if(elem) {
setChildColor(elem)
}
}