React はカスタマイズ可能な色を使用して SVG アイコン ライブラリをどのように設定しますか (2)

SVGカラー部分の処理

想定される用途は次のようなものです。

<Icon name="account" color="red" size={
    
    [50,50]}/>
或者 size={
    
    50} 这样的写法

したがって、次の 3 つのパラメータが必要です。

  • 名前
  • サイズ

前の記事の手順を実行すると、名前の要件が実現されたことがわかります。

size の実装は比較的単純なので、あまり詳しくは説明しません (size の処理プロセスは次のコードにも反映されています)、属性を svg に直接追加するだけです。簡単な例を見てみましょう。

return (
    <svg
      width={
    
    200}  // 把这里换成变量就可以了,或者将样式统一放在一个对象里,然后用展开符也行
      height={
    
    200}
      aria-hidden="true"
    >
      <use xlinkHref={
    
    iconName} />
    </svg>
  )

色の処理に関しては、2 つの異なる要件があります:
1 つは、元の SVG に付属する色を直接削除すること、およびすべての色はユーザーによってリセットされる (またはデフォルトの色を持つ) こと、もう 1 つはユーザー
がcolor 属性を渡しました 使用する場合はカスタム カラーのみを使用し、それ以外の場合は元の SVG カラーを維持します (これは私の要件でもあります)

これら 2 つの異なる要件では、処理スキームが異なります (svg-sprite-loader が使用される場合のみ)。最初の要件は実装が比較的簡単ですが、2 番目の要件はより面倒ですが、これについては後で別途説明します (場合によっては、私には実践がないので、アイデアや参考文献のみを示します)。

(1) 元のSVGカラーを削除する

いくつかのアイデアがあります:
1. 元の SVG 画像の fill のカラー値を直接削除する;
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. Web サイトの異なるテーマを切り替える実装と同様に、異なる CSS ファイルを動的に導入します (ただし、これは成功しませんでした) 2.
js セレクターを使用して、ID に従って対応するタグを選択します、ユーザーが color 属性をラベルに追加するとき。

2 番目の方法は、いくつかの方法を試して失敗した後、最終的に採用した方法ですが、アイデアは非常に単純で、svg-sprite-loader を使用した後に HTML ページを分析すると、各 svg 画像に対応するシンボル ID が異なることがわかります。 . ; シンボル タグの子は SVG イメージのパスであり、fill属性はタグの色を制御します。このようにして、 を使用してdocument.getElementById()このsymbolタグを選択し、 を使用してchildrenその子要素を取得し、fillパス内の属性を制御できます。このように、ユーザーが色を渡さない場合、

svg-sprite-loader 使用後の HTML

私のプロジェクトのディレクトリ構造は次のようになります。

- icons
	- svg 这个文件夹用来放所有的svg图片
- src
	- app.js 

アイコン.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 からダウンロードしたもので、構造は比較的均一です。たとえば、account.svg 画像の構造にはパスのラベルのみが含まれています。
ここに画像の説明を挿入

ただし、プロジェクトでは、デザイナーが提供する一部の SVG 画像にさらに多くのレイヤーとタグがあり (たとえば、rect や g などの複数のタグがあります)、color 属性ではどのタグの塗りつぶしが含まれているかがわかりません。画像の色は上記のように 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