Osadzanie SVG w ReactJS

132

Czy jest możliwe osadzenie znaczników SVG w komponencie ReactJS?

render: function() {
  return (
    <span>
      <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmln ...
    </span>
  );
}

Skutkuje błędem:

Atrybuty przestrzeni nazw nie są obsługiwane. ReactJSX to nie XML.

Jaki jest najlżejszy sposób na zrobienie tego. Używanie czegoś takiego jak React ART jest przesadą w tym, co próbuję zrobić.

mikołaja
źródło
1
Czy potrafisz stworzyć plik jsbin? Może to być tak proste, jak zmiana otwierającego tagu SVG na just <svg id="Layer_1">(lub nawet lepiej, bez identyfikatora). Edycja: oto przykład: jsbin.com/nifemuwi/2/edit?js,output
Brigand
@FakeRainBrigand Thanks! W tym przypadku było to takie proste. Spójrz jednak na odpowiedź Bena. Dobrze wiedzieć, że możesz obejść parsowanie jsx, kiedy zajdzie taka potrzeba.
Nicholas

Odpowiedzi:

187

Aktualizacja 2016-05-27

Począwszy od React v15, obsługa SVG w Reakcie jest (bliska?) 100% parzystości z obecną obsługą SVG przez przeglądarkę ( źródło ). Wystarczy zastosować pewne przekształcenia składni, aby był kompatybilny z JSX, tak jak już musisz to zrobić dla HTML ( classclassName, style="color: purple"style={{color: 'purple'}}). W przypadku dowolnego atrybutu z przestrzenią nazw (rozdzielanego dwukropkami), np. xlink:hrefUsuń :i zamień drugą część atrybutu wielką literą, np xlinkHref. Oto przykład z SVG <defs>, <use>i stylów inline:

function SvgWithXlink (props) {
    return (
        <svg
            width="100%"
            height="100%"
            xmlns="http://www.w3.org/2000/svg"
            xmlnsXlink="http://www.w3.org/1999/xlink"
        >
            <style>
                { `.classA { fill:${props.fill} }` }
            </style>
            <defs>
                <g id="Port">
                    <circle style={{fill:'inherit'}} r="10"/>
                </g>
            </defs>

            <text y="15">black</text>
            <use x="70" y="10" xlinkHref="#Port" />
            <text y="35">{ props.fill }</text>
            <use x="70" y="30" xlinkHref="#Port" className="classA"/>
            <text y="55">blue</text>
            <use x="0" y="50" xlinkHref="#Port" style={{fill:'blue'}}/>
        </svg>
    );
}

Działające demo codepen

Aby uzyskać więcej informacji na temat określonej obsługi, sprawdź listę obsługiwanych atrybutów SVG w dokumentacji . A oto (teraz zamknięty) problem z GitHub, który śledził obsługę atrybutów SVG w przestrzeni nazw.


Poprzednia odpowiedź

Możesz wykonać proste osadzenie SVG bez konieczności używania, dangerouslySetInnerHTMLpo prostu usuwając atrybuty przestrzeni nazw. Na przykład to działa:

        render: function() {
            return (
                <svg viewBox="0 0 120 120">
                    <circle cx="60" cy="60" r="50"/>
                </svg>
            );
        }

W którym momencie możesz pomyśleć o dodaniu rekwizytów, takich jak filllub cokolwiek innego, co może być przydatne do skonfigurowania.

Andrew Patton
źródło
@ChinonsoChukwuogor Świetne pytanie! Nie wiem, nigdy nie korzystałem z React Native. Czy spróbowałeś?
Andrew Patton,
@AndrewPatton Wiele nazw klas Css ze znakiem zaznaczenia nie działa: ' .class1, .class2{fill: #005baa;}' Jak mogę to naprawić?
HelloWorld,
@HelloWorld Czy możesz podać przykład, w którym to nie działa? Właśnie dodałem moje oryginalne demo classBi zadziałało: codepen.io/acusti/pen/BVJzNg
Andrew Patton
Dzięki, zaczynając od tego udało mi się zaimportować svg z pliku jako komponent Reacta bez żadnego programu ładującego, właśnie usunąłem `` xmlns: osb = " openswatchbook.org/uri/2009/osb " '' z tag svg, pozostawiając tylko xlmns. Najwyraźniej chodzi o analizowanie tagów. Na wszelki wypadek wykonałem również następujące kroki: blog.logrocket.com/how-to-use-svgs-in-react
funder7
Dlaczego ludzie tolerują JSX?
jordanfb
59

Jeśli masz tylko statyczny ciąg svg, który chcesz dołączyć, możesz użyć dangerouslySetInnerHTML:

render: function() {
    return <span dangerouslySetInnerHTML={{__html: "<svg>...</svg>"}} />;
}

a React doda znaczniki bezpośrednio, bez ich przetwarzania.

Sophie Alpert
źródło
3
Kontroluję niektóre ścieżki wewnątrz SVG za pomocą Reacta, ale React nie obsługuje elementów filtrujących. Czy jest sposób, aby to wesprzeć? Wygląda na to, że niebezpiecznie SetInnerHTML nie zadziała, ponieważ nie mogę umieścić zakresu w pliku SVG i nie mogę go użyć do ustawienia atrybutu filtru na ścieżkach. Nie sądzę, że istnieje sposób na normalne tworzenie elementów React, ale czy przekazują one wszystkie atrybuty dosłownie do elementów DOM?
Andy
Wydaje się, że w 2019 roku możesz używać niebezpiecznie SetInnerHTML, ale nadal nie mogłem sprawić, by filtr cienia działał w Chrome przy użyciu niebezpiecznego SetInnerHTML, ale działa on w przeglądarce Firefox.
Shnd
31

Według autora React nie potrzebujesz przestrzeni nazw xmlns. Jeśli potrzebujesz atrybutu xlink:href, możesz użyć xlinkHref z reakcji 0.14

Przykład

Icon = (props) => {
  return <svg className="icon">
    <use xlinkHref={ '#' + props.name }></use>
  </svg>;
}
lastid
źródło
12

Jeśli chcesz załadować go z pliku, możesz spróbować użyć React-inlinesvg - to całkiem proste i nieskomplikowane.

import SVG from 'react-inlinesvg';

<SVG
  src="/path/to/myfile.svg"
  preloader={<Loader />}
  onLoad={(src) => {
    myOnLoadHandler(src);
  }}
>
  Here's some optional content for browsers that don't support XHR or inline
  SVGs. You can use other React components here too. Here, I'll show you.
  <img src="/path/to/myfile.png" />
</SVG>
Youkko
źródło
1

Możesz zaimportować plik SVG i używać go jak obrazu

import chatSVG from '../assets/images/undraw_typing_jie3.svg'

I umieść to w tagu img

<img src={chatSVG} className='iconChat' alt="Icon chat"/>
Demetrio Gomez
źródło