将 SVG 组件作为背景图像反应到 div
React SVG component as background-image to div
我试图让 styled-components 获取作为 React 组件的 SVG 并将其设置为背景图像,但我收到错误:
TypeError: Cannot convert a Symbol value to a string
SVG 组件代码:
import React from "react";
const testSVG = props => {
return (
<svg version="1.1" id="Layer_1" x="0px" y="0px" viewBox="0 0 193.3 129.7">
<g>
<g>
<g>
<path
fill="#434343"
class="st0"
d="M162.4,116c-4.6,7.5-15.6,13.6-24.4,13.6H16c-8.8,0-12.3-6.2-7.7-13.7c0,0,4.6-7.7,11.1-18.4
c4.4-7.4,8.9-14.7,13.3-22.1c1.1-1.8,6.1-7.7,6.1-10.1c0-7.3-15-24.9-18.5-30.7C13.5,23.6,8.3,14.9,8.3,14.9
C3.7,7.4,7.2,1.2,16,1.2c0,0,65.9,0,106.8,0c10,0,25.9-4.5,33.5,3.8c8.7,9.3,15.5,25.4,22.5,36.8c2.6,4.2,14.5,18.3,14.5,23.8
c-0.1,7.6-16,26.1-19.6,32C167.1,108.3,162.4,116,162.4,116z"
/>
</g>
</g>
</g>
</svg>
);
};
export default testSVG;
容器组件代码:
import React, { Component } from "react";
import StepSVG from "../../components/UI/SVGs/Test";
class StepBar extends Component {
render() {
const { steps } = this.props;
return (
<div>
{steps
? steps.map(step => {
return (
<Wrap key={step._id} bg={StepSVG}>
<P>
{" "}
<Link to={"/step/" + step._id}>{step.title} </Link>
</P>
</Wrap>
);
})
: null}
</div>
);
}
}
export default StepBar;
const Wrap = styled.div`
padding: 30px 30px 0 0;
display: inline-block;
background-image: url(${props => props.bg});
`;
我正在使用开箱即用的 create-react-app。
我也尝试过不使用样式化组件并使用内联样式但没有成功。
是否可以在这种情况下将 SVG 用作背景图像并将 SVG 作为组件?
很遗憾,您想要实现的目标是不可能的。您必须将 SVG 保留为实际的 .svg 文件(并且 link 到那个),或者做一些 CSS 技巧将 SVG 组件放在前景组件后面。
换句话说:
<!-- step.svg -->
<svg version="1.1" id="Layer_1" x="0px" y="0px" viewBox="0 0 193.3 129.7">
<!-- copy paste your svg here -->
</svg>
在你的组件中:
import stepSvgUrl from "../../components/UI/SVGs/step.
// ...
<Wrap key={step._id} bg={stepSvgUrl}>
当您导入这样的 SVG 文件时,create-react-app 会将包含生成的 URL 的 Webpack 加载程序应用到您正在导入的 SVG - 可以传递到 background-image
css 属性.
希望对您有所帮助!
您可能应该将其转换为字符串(正如错误指出的那样)。显然你不能使用 React 组件作为背景图片,因为 React 组件实际上是一个 javascript 对象(JSX 转换为 JS,然后转换为 HTML)。所以你可以 do/try 使用 ReactDOMServer (https://reactjs.org/docs/react-dom-server.html).
你可以试试:
ReactDOMServer.renderToString(StepSVG)
或
ReactDOMServer.renderToStaticMarkup(StepSVG)
我还没有测试过这是否真的有效,但我想你值得一试:)
实际上,有一种方法可以实现您想要的效果,而无需将 SVG 作为组件:
这是更新后的 StepBar
组件:
import React, { Component } from "react";
import StepSVG from "../../components/UI/SVGs/test.svg";
import encodeSVG from '../../lib/encodeSVG';
class StepBar extends Component {
render() {
const { steps } = this.props;
return (
<div>
{steps
? steps.map(step => {
return (
<Wrap key={step._id} bg={StepSVG}>
<P>
{" "}
<Link to={"/step/" + step._id}>{step.title} </Link>
</P>
</Wrap>
);
})
: null}
</div>
);
}
}
export default StepBar;
const Wrap = styled.div`
padding: 30px 30px 0 0;
display: inline-block;
background-image: ${encodeSVG(bg, '#FF9900')};
`;
这里是 encodeSVG
库文件:
var symbols = /[\r\n"%#()<>?\[\\]^`{|}]/g;
function addNameSpace(data) {
if (data.indexOf('http://www.w3.org/2000/svg') < 0) {
data = data.replace(/<svg/g, "<svg xmlns='http://www.w3.org/2000/svg'");
}
return data;
}
function encodeSVG(data) {
// Use single quotes instead of double to avoid encoding.
if (data.indexOf('"') >= 0) {
data = data.replace(/"/g, "'");
}
data = data.replace(/>\s{1,}</g, '><');
data = data.replace(/\s{2,}/g, ' ');
return data.replace(symbols, encodeURIComponent);
}
var encode = function(svg, fill) {
if (fill) {
svg = svg.replace(/<svg/g, `<svg fill="${fill}"`);
}
var namespaced = addNameSpace(svg);
var dimensionsRemoved = namespaced
.replace(/height="\w*" /g, '')
.replace(/width="\w*" /g, '')
.replace(/height='\w*' /g, '')
.replace(/width='\w*' /g, '');
var encoded = encodeSVG(dimensionsRemoved);
var header = 'data:image/svg+xml,';
var dataUrl = header + encoded;
return `url("${dataUrl}")`;
};
您导入 svg,并在您首选的构建系统(例如 WebPack)中使用 svg 的字符串加载器,将该 svg 传递给 encodeSVG,等等! :)
url(`data:image/svg+xml;utf8,${svgTxt}`)
;或
url(`data:image/svg+xml;base64,${btoa(svgTxt)}`)
就是这样。
对于 React SVG 背景图片,我发现这个效果最好:
// MyComponent.js
import mySvg from './mySvg.svg';
...
function MyComponent() {
return (
<div
className="someClassName"
style={{ backgroundImage: `url(${mySvg})` }}
>
... etc
当 webpack 打包时,SVG 文件的路径会改变,所以通过使用模板字符串你可以保持联系。
在 CSS class 中,您可以随意设置自己喜欢的样式。
我最终结合使用 user11011301 的解决方案和 raw-loader 来加载 SVG 内容。我确定这不是最干净的解决方案,但我无法让它与其他 webpack 加载器一起工作。
import searchIcon from '../../images/search.svg';
<input style={{backgroundImage: `url(data:image/svg+xml;base64,${btoa(searchIcon)})`}}/>
我试图让 styled-components 获取作为 React 组件的 SVG 并将其设置为背景图像,但我收到错误:
TypeError: Cannot convert a Symbol value to a string
SVG 组件代码:
import React from "react";
const testSVG = props => {
return (
<svg version="1.1" id="Layer_1" x="0px" y="0px" viewBox="0 0 193.3 129.7">
<g>
<g>
<g>
<path
fill="#434343"
class="st0"
d="M162.4,116c-4.6,7.5-15.6,13.6-24.4,13.6H16c-8.8,0-12.3-6.2-7.7-13.7c0,0,4.6-7.7,11.1-18.4
c4.4-7.4,8.9-14.7,13.3-22.1c1.1-1.8,6.1-7.7,6.1-10.1c0-7.3-15-24.9-18.5-30.7C13.5,23.6,8.3,14.9,8.3,14.9
C3.7,7.4,7.2,1.2,16,1.2c0,0,65.9,0,106.8,0c10,0,25.9-4.5,33.5,3.8c8.7,9.3,15.5,25.4,22.5,36.8c2.6,4.2,14.5,18.3,14.5,23.8
c-0.1,7.6-16,26.1-19.6,32C167.1,108.3,162.4,116,162.4,116z"
/>
</g>
</g>
</g>
</svg>
);
};
export default testSVG;
容器组件代码:
import React, { Component } from "react";
import StepSVG from "../../components/UI/SVGs/Test";
class StepBar extends Component {
render() {
const { steps } = this.props;
return (
<div>
{steps
? steps.map(step => {
return (
<Wrap key={step._id} bg={StepSVG}>
<P>
{" "}
<Link to={"/step/" + step._id}>{step.title} </Link>
</P>
</Wrap>
);
})
: null}
</div>
);
}
}
export default StepBar;
const Wrap = styled.div`
padding: 30px 30px 0 0;
display: inline-block;
background-image: url(${props => props.bg});
`;
我正在使用开箱即用的 create-react-app。
我也尝试过不使用样式化组件并使用内联样式但没有成功。
是否可以在这种情况下将 SVG 用作背景图像并将 SVG 作为组件?
很遗憾,您想要实现的目标是不可能的。您必须将 SVG 保留为实际的 .svg 文件(并且 link 到那个),或者做一些 CSS 技巧将 SVG 组件放在前景组件后面。
换句话说:
<!-- step.svg -->
<svg version="1.1" id="Layer_1" x="0px" y="0px" viewBox="0 0 193.3 129.7">
<!-- copy paste your svg here -->
</svg>
在你的组件中:
import stepSvgUrl from "../../components/UI/SVGs/step.
// ...
<Wrap key={step._id} bg={stepSvgUrl}>
当您导入这样的 SVG 文件时,create-react-app 会将包含生成的 URL 的 Webpack 加载程序应用到您正在导入的 SVG - 可以传递到 background-image
css 属性.
希望对您有所帮助!
您可能应该将其转换为字符串(正如错误指出的那样)。显然你不能使用 React 组件作为背景图片,因为 React 组件实际上是一个 javascript 对象(JSX 转换为 JS,然后转换为 HTML)。所以你可以 do/try 使用 ReactDOMServer (https://reactjs.org/docs/react-dom-server.html).
你可以试试:
ReactDOMServer.renderToString(StepSVG)
或
ReactDOMServer.renderToStaticMarkup(StepSVG)
我还没有测试过这是否真的有效,但我想你值得一试:)
实际上,有一种方法可以实现您想要的效果,而无需将 SVG 作为组件:
这是更新后的 StepBar
组件:
import React, { Component } from "react";
import StepSVG from "../../components/UI/SVGs/test.svg";
import encodeSVG from '../../lib/encodeSVG';
class StepBar extends Component {
render() {
const { steps } = this.props;
return (
<div>
{steps
? steps.map(step => {
return (
<Wrap key={step._id} bg={StepSVG}>
<P>
{" "}
<Link to={"/step/" + step._id}>{step.title} </Link>
</P>
</Wrap>
);
})
: null}
</div>
);
}
}
export default StepBar;
const Wrap = styled.div`
padding: 30px 30px 0 0;
display: inline-block;
background-image: ${encodeSVG(bg, '#FF9900')};
`;
这里是 encodeSVG
库文件:
var symbols = /[\r\n"%#()<>?\[\\]^`{|}]/g;
function addNameSpace(data) {
if (data.indexOf('http://www.w3.org/2000/svg') < 0) {
data = data.replace(/<svg/g, "<svg xmlns='http://www.w3.org/2000/svg'");
}
return data;
}
function encodeSVG(data) {
// Use single quotes instead of double to avoid encoding.
if (data.indexOf('"') >= 0) {
data = data.replace(/"/g, "'");
}
data = data.replace(/>\s{1,}</g, '><');
data = data.replace(/\s{2,}/g, ' ');
return data.replace(symbols, encodeURIComponent);
}
var encode = function(svg, fill) {
if (fill) {
svg = svg.replace(/<svg/g, `<svg fill="${fill}"`);
}
var namespaced = addNameSpace(svg);
var dimensionsRemoved = namespaced
.replace(/height="\w*" /g, '')
.replace(/width="\w*" /g, '')
.replace(/height='\w*' /g, '')
.replace(/width='\w*' /g, '');
var encoded = encodeSVG(dimensionsRemoved);
var header = 'data:image/svg+xml,';
var dataUrl = header + encoded;
return `url("${dataUrl}")`;
};
您导入 svg,并在您首选的构建系统(例如 WebPack)中使用 svg 的字符串加载器,将该 svg 传递给 encodeSVG,等等! :)
url(`data:image/svg+xml;utf8,${svgTxt}`)
;或
url(`data:image/svg+xml;base64,${btoa(svgTxt)}`)
就是这样。
对于 React SVG 背景图片,我发现这个效果最好:
// MyComponent.js
import mySvg from './mySvg.svg';
...
function MyComponent() {
return (
<div
className="someClassName"
style={{ backgroundImage: `url(${mySvg})` }}
>
... etc
当 webpack 打包时,SVG 文件的路径会改变,所以通过使用模板字符串你可以保持联系。
在 CSS class 中,您可以随意设置自己喜欢的样式。
我最终结合使用 user11011301 的解决方案和 raw-loader 来加载 SVG 内容。我确定这不是最干净的解决方案,但我无法让它与其他 webpack 加载器一起工作。
import searchIcon from '../../images/search.svg';
<input style={{backgroundImage: `url(data:image/svg+xml;base64,${btoa(searchIcon)})`}}/>