有一个需求是这样的。
一个组件里若干个区块。区块数量不定。
区块里面是一个波浪效果组件,而这个一般用 SVG 做。
所以就变成了在 react 中使用 SVG 的问题。
首先是波浪效果需要的样式。
.p{ font-size: 12px; line-height: 2; text-align: center; margin:0; width: 52px; color: #fff; } .irrigate_svg { height: 52px; width: 52px; } .masked { -webkit-mask: url(#myMask); mask: url(#myMask); } .irrigate_wrap { transform: translateY(112px); } .irrigate_svg { overflow: hidden; } .irrigate_rate { animation-name:wavingleft, wavingUp; animation-duration:6s, 6s; animation-timing-function:linear, linear; animation-iteration-count:infinite, 1; } @keyframes wavingleft { 0% { transform: translateX(-239px); } 50% { transform: translateX(0px); } 100% { transform: translateX(-239px); } } @keyframes wavingright { 0% { transform: translateX(0px); } 50% { transform: translateX(-239px); } 100% { transform: translateX(0px); } } @keyframes wavingUp{ 0% { transform: translateX(-239px) translateY(100px); } 50% { transform: translateX(0px); } 100% { transform: translateX(-239px) translateY(0px); } }
引入样式,以及组件文件的结构。
import React from 'react' import Styles from './waveContainer.less' class Wave extends React.Component {} class WaveContainer extends React.Component {} export default WaveContainer
一个组件文件里可能有很多层组件,只需要输出最外面的一层。
SVG 组件。
class Wave extends React.Component { constructor(props){ super(props) this.state = { } } render(){ const item = this.props.data const getNumberPosition = (number) => { let style const s = { s1:"matrix(1 0 0 1 96.44 150)", s2:"matrix(1 0 0 1 66.44 150)", s3:"matrix(1 0 0 1 46.44 150)", } switch (parseInt(number).toString().length) { case 0: style = s.s2 break; case 1: style = s.s1 break; case 2: style = s.s2 break; case 3: style = s.s3 break; default: style = s.s2 } return style } const getColor = (item) => { return item.color } return ( <div > <div className={Styles.irrigate_svg}> <svg version="1.1" id="图层_5" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" viewBox="0 0 244.2 244.2" style={{ enableBackground:"new 0 0 244.2 244.2" }} > <defs> <mask id="myMask"> <circle style={{ fill:"#fff",stroke:"#fff","strokeMiterlimit":"10" }} cx="122.1" cy="122.1" r="122.1"/> </mask> </defs> <g className={Styles.masked}> <g className={Styles.irrigate_wrap}> {/* <linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="1120.8899" y1="262.1278" x2="1120.8899" y2="1.81" gradientTransform="matrix(-1 0 0 -1 1430.8899 246)"> <stop offset="0" style={{ stopColor:getColor(item),"stopOpacity":"0.8" }}/> <stop offset="1" style={{ stopColor:getColor(item),"stopOpacity":"0.7"}}/> </linearGradient> */} <path className={Styles.irrigate_rate} style={{ fill:getColor(item) }} d="M0-3.8c0,0,44.7-14.3,77-12.1c32.9,2.3,95.6,33.3,128.3,31.1c38.9-2.6,116.7-33.7,153-29.7 c22.9,2.5,73,20.4,95.7,24.4c30.9,5.5,64.2,8.4,90.3,6.8C567.8,15.2,620-3.8,620-3.8v248H0V-3.8z"/> </g> </g> <g> <g id="图层_5-2"> <circle style={{ fill:"none",stroke:"#25437C",strokeWidth:"1",strokeMiterlimit:"1" }} cx="122.1" cy="122.1" r="122.1"/> <text transform={getNumberPosition(item.data)} style={{ fill:"#FFF", fontSize:"100px" }}> {item.data} </text> <linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="0" y1="123.91" x2="244.18" y2="123.91" gradientTransform="matrix(1 0 0 -1 0 246)"> <stop offset="0" style={{ stopColor:"rgb(55,107,112)" }}/> <stop offset="1" style={{ stopColor:"rgb(55,107,112)" }}/> </linearGradient> <circle style={{ fill:"none",stroke:"url(#SVGID_3_)",strokeWidth:"1",strokeLinecap:"round",strokeMiterlimit:"1" }} cx="122.1" cy="122.1" r="122.1"/> </g> </g> </svg> </div> <p className={Styles.p}> {item.name} </p> </div> ); } }
SVG原本怎么写,JSX就怎么写。
但是遇到了一个问题。
linearGradient, 这个用来做渐变的标签,直接使用没有问题,但如果循环输出的时候把需要的值赋值进去,就会发现所有 SVG 组件的颜色都和第一个一样了。而用开发者工具查看的时候,颜色确实是赋值进去了。不知道是怎么回事。
然后是容器组件。
class WaveContainer extends React.Component { constructor(props){ super(props) this.state = { } } render(){ const baseFlex = { display: 'flex', justifyContent: 'center', alignItems: 'center' } const theStyle = { main:{ ...baseFlex, width:'100%', height:'100%', color:"#fff" }, tem:{ ...baseFlex, flex:"auto", color:'#fff' }, shellA:{ ...baseFlex, width:'100%', height:'100%' }, shellB:{ ...baseFlex, width:'100%', height:'50%' } } // const dataBar = this.props.dataBar const dataBar = (() => { if (this.props.curcity && this.props.curcity === 'all') { return { data:{ sData:[ { name: 'a', data: 55, color:'rgb(79,239,223)' }, { name: 'a', data: 5, color:'rgb(79,239,223)'}, { name: 'a', data: 36, color:'rgb(79,239,223)'}, { name: 'a', data: 476, color:'rgb(87,207,30)'}, { name: 'a', data: 226, color:'rgb(79,239,223)'}, { name: 'a', data: 273, color:'rgb(251,211,36)'} ] } } } else { return { data:{ sData:[ { name: 'a', data: 124, color:'rgb(79,239,223)' }, { name: 'a', data: 253, color:'rgb(79,239,223)'}, { name: 'a', data: 321, color:'rgb(79,239,223)'}, { name: 'a', data: 156, color:'rgb(87,207,30)'}, { name: 'a', data: 2, color:'rgb(79,239,223)'}, { name: 'a', data: 77, color:'rgb(251,211,36)'} ] } } } })() const Container = ((dataBar) => { const flexMatrix = [ [0,0], [1,0], [2,0], [3,0], [2,2], [3,2], [3,3], [4,3], [4,4], [5,4], [5,5], [6,5], [6,6] ] const sData = dataBar.data.sData const length = sData.length const matrix = flexMatrix[length] ? flexMatrix[length] : flexMatrix[12] if (matrix[0] === 0) { return "" } let temShell, temA, temB temA = sData.slice(0, matrix[0]).map((item, index) => <div style={theStyle.tem} key={index.toString()}> <Wave data={item} /> </div> ); if (matrix[1] === 0) { temB = "" } else { temB = sData.slice(matrix[0], (matrix[0] + matrix[1])).map((item, index) => <div style={theStyle.tem} key={index.toString()}> <Wave data={item} /> </div> ); } if (matrix[1] === 0) { temShell = <div style={theStyle.shellA} > {temA} </div> } else { temShell = [0,0].map((item, index) => <div style={theStyle.shellB} key={"temShell" + index.toString()}> {index === 0 ? temA : temB} </div> ); theStyle.main.flexWrap = "wrap" } console.log(temShell) return temShell })(dataBar) return ( <div style={theStyle.main}> {/* <Wave /> */} { Container } </div> ); } }
以上。