• react实战 : react 与 svg


    有一个需求是这样的。

    一个组件里若干个区块。区块数量不定。

    区块里面是一个波浪效果组件,而这个一般用 SVG 做。

    所以就变成了在 react 中使用 SVG 的问题。

    首先是波浪效果需要的样式。

    .p{
      font-size: 12px;
      line-height: 2;
      text-align: center;
      margin:0;
       52px;
      color: #fff;
    }
    
    .irrigate_svg {
      height: 52px;
       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,
            '100%',
            height:'100%',
            color:"#fff"
          },
          tem:{
            ...baseFlex,
            flex:"auto",
            color:'#fff'
          },
          shellA:{
            ...baseFlex,
            '100%',
            height:'100%'
          },
          shellB:{
            ...baseFlex,
            '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>
        );
      }
    }

    以上。

  • 相关阅读:
    为什么整个互联网行业都缺前端工程师?
    css3做的圆特效
    又一个前端的小渣渣诞生了
    返回顶部代码!
    网页动画的十二原则
    JQuery缓冲加载图片插件lazyload.js的使用方法
    关于写手机页面demo的准备工作
    HTML5加载动画
    HTML5加载动画
    正则表达式语法
  • 原文地址:https://www.cnblogs.com/foxcharon/p/11933649.html
Copyright © 2020-2023  润新知