반응은 사용자 정의 가능한 색상으로 svg 아이콘 라이브러리를 어떻게 설정합니까? (2)

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경로의 속성을 제어할 수 있습니다. 이와 같이 사용자가 색상을 전달하지 않을 때,

svg-sprite-loader 사용 후 HTML

내 프로젝트의 디렉토리 구조는 다음과 같습니다.

- 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)
    }
  }

추천

출처blog.csdn.net/Charonmomo/article/details/129788881