JSX 中的 SVG - 如何转换 defs 标签

Posted

技术标签:

【中文标题】JSX 中的 SVG - 如何转换 defs 标签【英文标题】:SVG in JSX - how to convert defs tag 【发布时间】:2018-03-22 01:23:10 【问题描述】:

我有一些 SVG 有一个 defs 属性,里面有一个 style 标签。 像这样:

<svg ...>
  <defs>
    <style>.cls-1,.cls-7fill:#b2488d;.cls-1,.cls-2,.cls-3,.cls-4,.cls-5,.cls-6stroke:#671f4d;</style>
  </defs>
  ...
</svg>

我想在 React 中使用这些 SVG,所以我想将它们转换为有效的 JSX。我已经使用过svg2jsx 之类的工具,但它们会去掉defs 标记,因此不再存在任何样式属性。有没有办法通过在JSX中转换SVG来保留defsstyle标签?还是在这种情况下不能使用 css 类?

【问题讨论】:

必须转换吗?你不能在你的html中使用&lt;img src="/images/logo.svg" /&gt;或者在你的css中使用background-image: url("/images/logo.svg");吗? @cyonder 内联 SVG 在大多数浏览器中得到更好的支持 我想使用 SVG 来操作属性。 你想如何操作它们?您想在 svg 标签元素中使用状态/道具吗? @lumio 是的,这就是我想做的。 【参考方案1】:

您可以保留样式而无需任何转换。为此,使用 ` 和 ` 将样式标签内的所有 CSS 类包装起来。 现在你的 SVG 变成了这样

<svg ...>
  <defs>
    <style>`.cls-1,.cls-7fill:#b2488d;.cls-1,.cls-2,.cls-3,.cls-4,.cls-5,.cls-6stroke:#671f4d;`</style>
  </defs>
  ...
</svg>

这将毫无问题地呈现。

【讨论】:

【参考方案2】:

如果您在 Illustter 中创建了 SVG,请将其保存,并将 CSS 属性 设置为 Presentation Attributes。这样一来,您就不会得到一个 CSS 类,并且可以直接更改所有属性。

我导出了一个看起来像这样的 SVG:

<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 21.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
     viewBox="0 0 100 100" enable-background="new 0 0 100 100" xml:space="preserve">
<g>
    <rect x="15.5" y="15.5" fill="#FFFFFF"  />
    <path d="M59,16v43H16V16H59 M60,15H15v45h45V15L60,15z"/>
</g>
<g>
    <path fill="#FFFFFF" d="M60.5,81.5c-12.1,0-22-9.9-22-22s9.9-22,22-22s22,9.9,22,22S72.6,81.5,60.5,81.5z"/>
    <path d="M60.5,38C72.4,38,82,47.6,82,59.5S72.4,81,60.5,81S39,71.4,39,59.5S48.6,38,60.5,38 M60.5,37C48.1,37,38,47.1,38,59.5
        S48.1,82,60.5,82S83,71.9,83,59.5S72.9,37,60.5,37L60.5,37z"/>
</g>
</svg>

然后我去掉了所有不需要的标记,只在我的组件中使用它:

const Image = ( props ) => 
  const 
    hideSquare,
    hideCircle,
   = props;
  
  const colorSquare = props.colorSquare || '#fff';
  const colorCircle = props.colorCircle || '#fff';
  
  return (
    <svg x="0px" y="0px" viewBox="0 0 100 100">
       hideSquare ? null : (
        <g>
          <rect x="15.5" y="15.5" fill= colorSquare   />
          <path d="M59,16v43H16V16H59 M60,15H15v45h45V15L60,15z"/>
        </g>
      ) 
       hideCircle ? null : (
        <g>
          <path fill= colorCircle  d="M60.5,81.5c-12.1,0-22-9.9-22-22s9.9-22,22-22s22,9.9,22,22S72.6,81.5,60.5,81.5z"/>
          <path d="M60.5,38C72.4,38,82,47.6,82,59.5S72.4,81,60.5,81S39,71.4,39,59.5S48.6,38,60.5,38 M60.5,37C48.1,37,38,47.1,38,59.5
            S48.1,82,60.5,82S83,71.9,83,59.5S72.9,37,60.5,37L60.5,37z"/>
        </g>
      ) 
    </svg>
  );
;

class Wrapper extends React.Component 
  constructor( props ) 
    super( props );
    
    // Set default state
    this.state = 
      selectedColor: 'lightgreen',
      hideSquare: false,
      hideCircle: false,
    ;
  
  
  // onInput callback
  changeColor = ( e ) => 
    this.setState(  selectedColor: e.target.value  );
  
  
  changeVisibility = ( e ) => 
    const  name, checked  = e.target;
    this.setState(  [ name ]: checked  );
  
  
  render() 
    return (
      <div>
        <select onInput= this.changeColor >
          <option>lightgreen</option>
          <option>pink</option>
          <option>red</option>
        </select><br />
        <label><input type="checkbox" name="hideSquare" onChange= this.changeVisibility  /> hideSquare</label>
        <label><input type="checkbox" name="hideCircle" onChange= this.changeVisibility  /> hideCircle</label><br />
        <Image
          hideSquare= this.state.hideSquare 
          hideCircle= this.state.hideCircle 
          colorSquare= this.state.selectedColor 
          colorCircle= this.state.selectedColor 
        />
      </div>
    );
  


ReactDOM.render( <Wrapper />, document.getElementById( 'app' ) );
svg 
  width: 200px;
  height: 200px;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>

【讨论】:

后者是否允许我使用 React 状态值更改属性值?如,字符串插值会起作用吗? 我更新了我的答案。 tl;dr:您需要在不生成 CSS 样式的情况下导出 SVG。 :) 这并不能完全回答我的问题,但是我发现它是解决我的问题的好方法。

以上是关于JSX 中的 SVG - 如何转换 defs 标签的主要内容,如果未能解决你的问题,请参考以下文章

多个 SVG 标签中的 clipPath

将 svg 标签转换为图像中的嵌入 svg

VS Code - 格式化时如何对齐标签结尾和标签开头? (JSX)

88svg子标签(示例)

如何将可变数量的道具传递给 React 中的 JSX 标签

如何在不改变坐标的情况下转换(旋转)svg文本元素?