520礼物,svg月亮鲜花动画(一、主体)

文章展示了如何利用SVG的stroke-dasharray和stroke-dashoffset属性以及React来构建一个520主题的互动按钮,按钮包含心形、月亮、花朵等元素的动画效果,点击按钮时会有不同的视觉变化。
摘要由CSDN通过智能技术生成

前几天在想520到了,要送什么礼物,最近正好又在做按钮动画。于是就做了这个月亮鲜花的svg效果。完整效果视频可以看我Dou音,DY号:G_console

下面是部分效果截图:

启动按钮
过程截图
背景效果

主要的实现思路就是利用svg的“stroke-dasharray”和“stroke-dashoffset”两个属性控制path线条的运动。

背景的3D效果放下一篇发,这一篇文章只放svg动画的代码。而且我做了一些精简,不然那几朵花的svg代码占的太多了。

React:

import cx from 'classnames';
import React from 'react';
import styles from './index.less';
const ButtonStart = () => {
  const width = 600;
  const height = 250;
  const wHarf = 300; // width/2
  const offset = 10;
  const radio = 50;
  return <svg version="1.1" 
    viewBox={"0 0 "+width+" "+height+""}
    height={height} width={width} style={{
      width: '100%',
      height: '100%'
    }}
  >
    <path className={styles.buttonBorder}
      d={'M '+wHarf+' '+offset+' L '+(radio+offset)+' '+offset+' Q '+offset+' '+offset+' '+offset+' '+(radio+offset)+' L '+offset+' '+(height-offset-radio) + ' Q '+offset+' '+(height-offset)+' '+(offset+radio)+' '+(height-offset)+' L '+(width-offset-radio)+' '+(height-offset)+' Q '+(width-offset)+' '+(height-offset)+' '+(width-offset)+' '+(height-offset-radio)+' L '+(width-offset)+' '+(offset+radio)+' Q '+(width-offset)+' '+offset+' '+(width-offset-radio)+' '+offset+'z'}
      strokeWidth={5} fill={'none'}
    />
    <g className={styles.heartOuter}>
      <path className={styles.heart} d="M300,184.7c0,0,71.17-48.88,71.17-84.17S324.42,47.58,300,90.52c-24.42-42.94-71.17-25.28-71.17,10.01  S300,184.7,300,184.7z" 
        strokeWidth={7} fill="none"
      ></path>
    </g>
    <path className={styles.start} d="M300,99.49c-13.09-7.44-48.07,1.86-48.44,8.93c-0.37,7.07,54.7,17.86,54.33,27.91s-70.03,17.86-71.34,4.09  c-0.15-7.63,6.22-5.95,6.22-5.95 M317.05,109.54c0,0,16,4.84,36.47,0 M327.47,88.33c0,0,2.23,18.42,0,43.53  c-0.44,8.74,1.49,23.81,24.19,14.14 M401.89,106.19c0,0-15.26-9.67-21.58-4.09s-14.88,40.12-11.16,45.73s31.53-24.94,33.95-41.73  c0,0-6.6,38.21-1.58,42.97 M428.86,106.75c0,0,4.09,25.12,2.42,43.63c0,0,3.53-38.6,30.14-42.51 M465.51,110.61  c0,0,12.28,2.27,35.91-1.07 M474.82,88.33c0,0,0.19,31.07,0,45.58c-0.19,14.51,11.16,17.86,23.63,12.84" 
      strokeWidth={7} fill="none"
    ></path>
  </svg>
}
const Moon = () => {
  return <svg version="1.1" 
    viewBox={"0 0 600 600"}
    style={{
      width: '100%',
      height: '100%'
    }}
  >
    <path className={styles.moon}
      d="M307.33,598C109.57,598,15.95,377.73,75.91,237.83S324.86,19.47,480.03,137.79c0,0-154.19-81.9-265.67,70.33  C136.21,314.81,191.04,500.58,331,513.42c116.36,10.67,205.31-49.16,240.56-141.21C571.56,372.21,542.07,598,307.33,598z"
    />
  </svg>
}
const Plants = ({
  
}: {
  
}) => {
  return <svg version="1.1" 
    viewBox={"0 0 600 600"}
    style={{
      width: '100%',
      height: '100%'
    }}
  >
    <g>
      <path className={cx(styles.pl2, styles.plAn1)} id="plAn1" d="M319.05,595.5c0,0,100.56,12.25,185.81-96.48c0,0,9.9-12.56,17.02-36.28"/>
      <path className={styles.pl3} cus-attr='plLf' style={{transformOrigin: '72% 94%'}} d="M432.27,564.11c0,0,49.01-29.93,31.85-64.26"/>
      <path className={styles.pl4} cus-attr='plLf' style={{transformOrigin: '77.9% 86.9%'}} d="M467.36,521.24c0,0,15.42-13.36,15.63-18.84s-7.43-5.09-9.28,12.28C473.71,514.68,473.88,515.76,467.36,521.24   z"/>
      <path className={styles.pl4} cus-attr='plLf' style={{transformOrigin: '77.8% 90%'}} d="M467.18,539.39c0,0,8.3-3.33,14.16-0.47s9.49,6.77,20.93,5.23c0,0-3.73-9.87-20.23-5.23   C482.05,538.92,476.67,535.99,467.18,539.39z"/>
      <path className={styles.pl4} cus-attr='plLf' style={{transformOrigin: '78% 90%'}} d="M467.6,538.94c0,0,8.09-8.67,18.98-11.32c10.88-2.65,19.95-1.88,25.4-1.05c5.44,0.84,12.35,6,17.44,0.42   c0,0-3.06-7.59-20.85-1.31c0,0,8.5-2.92,13.11-2.5c4.6,0.42,9.84-11.54-1.74-10.92c0,0-3.79,7.79-12.35,13.77   c0,0,13.46-9.37,12.97-18.86c0,0-13.74-2.58-13.6,17.93c0,0-0.21,0.45-5.06,0.45C497.05,525.56,481.49,525.07,467.6,538.94z"/>
      <path className={styles.pl4} cus-attr='plLf' style={{transformOrigin: '82% 86%'}} d="M492.62,514.16c3.54-8.06,2.21-4.33,4.36-11.47c0.01-0.04,1.05-8.27-0.41-14.1   c-7.67-5.16-7.02-11.54-7.01-11.58c0.01-0.04,4.85-1.09,6.73,5.2c1.9,6.34,0.83,20.02,0.84,19.98c2.69-9.1,5.2-22.54,3.13-37.35   c0.76-18.84,10.33-16.88,12.84-15.77c0,0-0.56,11.44-11.79,20.72c0,0-13.67-0.98-16.33-2.65c-2.65-1.67-7.81-12.63-7.33-13.74   c0.49-1.12,19.05-2.09,23.16,12.49c0,0-0.7-16.32,6.49-17.48c0,0-3.63-12.11-13.33-7.5c0,0-10.26-1.6-7.05,12.07   c0,0,14.3,4.33,14.37,17.86C501.37,484.37,499.77,497.55,492.62,514.16z"/>
      <path className={styles.pl4} cus-attr='plLf' style={{transformOrigin: '84% 84%'}} d="M502.8,501.91c0,0,8.97-7.19,12.73-7.4c3.77-0.21,12.28-1.5,14.83-7.08c0,0-8.06-2.37-15.45,6.94   C514.91,494.38,509.25,496.68,502.8,501.91z"/>
    </g>
    <g>
      <path className={cx(styles.pl2, styles.plAn2)} id="plAn2" d="M146.91,526.72c0,0-74.57-61.76-73.99-173.03c1.27-14.65,3.87-15.4,5.73-20.79   c1.86-5.4,13.02-53.95,17.12-75.72c4.09-21.77,32.56-74.42,70.51-104.74"/>
      <path className={styles.pl4} cus-attr='plLf2' style={{transformOrigin: '18.53% 80.77%'}} d="M111.19,484.64c0,0-22.67-45.7-98.95-33.42c0,0-11.16,26.42,18.6,21.58c29.77-4.84,26.42-2.14,53.12-13.95   c0,0-42.79-38.05-71.44-8C12.52,450.85,82.33,437.69,111.19,484.64z"/>
      <path className={styles.pl4} cus-attr='plLf2' style={{transformOrigin: '14.78% 73.49%'}} d="M88.7,440.95c0,0-13.86-18.65-21.12-23.95c-3.44-4.65-6.98-14.05-14.7-21.95s-9.95-9.12-18.51-23.26   c0,0-5,17.59,13.4,30.33c18.4,12.74,16.35,11.86,19.65,14.35c0,0-1.98-16.86-14.07-27.93c-12.09-11.07-18.7-16.98-19.47-18.28   c0,0,7.33,15.07,17.93,24.23c4.67,3.91,8.42,9.63,15.95,22.26C67.77,416.74,81.45,430.25,88.7,440.95z"/>
      <path className={styles.pl4} cus-attr='plLf2' style={{transformOrigin: '12.57% 65.21%'}} d="M75.4,391.27c0,0-4.37-8.88-18.7-22.28s-13.4-37.58-8.74-38.88c4.65-1.3,10.42,16,10.6,20.09   c0.19,4.09,1.26,15.3-0.84,19.21C57.73,369.41,70.1,381.55,75.4,391.27z"/>
      <path className={styles.pl4} cus-attr='plLf2' style={{transformOrigin: '12.18% 58.48%'}} d="M73.09,350.9c0,0-22.52-51.3,1.1-83.49c5.02-1.49,7.63,6.33,6.51,17.67c-3.16,9.3-11.3,8.37-16.33,31.02   C64.38,316.11,63.98,327.04,73.09,350.9z"/>
      <path className={styles.pl3} cus-attr='plLf2' style={{transformOrigin: '14.65% 49.19%'}} d="M87.91,295.13c0,0,21.81-50.23,60.33-44.84"/>
      <path className={styles.pl4} cus-attr='plLf2' style={{transformOrigin: '19.70% 42.91%'}} d="M118.19,257.46c0,0,13.26-31.26,17.35-31.44c4.09-0.19,3.21,12.12-11.42,18.88   C124.12,244.9,120.7,251.22,118.19,257.46z"/>
      <path className={styles.pl4} cus-attr='plLf2' style={{transformOrigin: '16.36% 41.23%'}} d="M98.19,247.41c0,0,3.81-9.3-3.81-28.74s-2.7-27.26,13.12-40.09c0,0,9.58,13.3-6.6,22.51   c-10.03,5.86-9.42,7.21-9.42,7.21s-6.53-13.58-14.07-20.09c0,0-2.14-10.79,0-10.74c2.14,0.05,10.98,9.3,14,19.58   c0,0,3.16-7.81,10.88-14.51c0,0-4.88-8.23-7.81-8.23s-10.14,9.11-9.83,9.7c0.32,0.58,7.55,9.79,6.15,17.98c0,0-3.4-9.16-5.72-11.67   c0,0,7.05,8,6.16,16.56c0,0,2.12-7.86,7.42-11.44c0,0-5.37,3.4-7.34,12.24c0.65,4.08,2.08,8.62,3.73,12.24   C96.7,223.53,101.12,239.97,98.19,247.41z"/>
      <path className={styles.pl4} cus-attr='plLf2' style={{transformOrigin: '20.98% 32.78%'}} d="M125.88,196.66c0,0,2.45-13.99,2.08-19.85c0,0-6.14-12.28,1.77-21.58c0,0,5.16,13.23-1.44,21.63   C128.28,176.85,128.18,180.97,125.88,196.66z"/>
      <path className={styles.pl3} cus-attr='plLf2' style={{transformOrigin: '18.26% 37.32%'}} d="M109.54,223.92c0,0,21.02-26.88,59.35-39.35c0,0,10.98-8.28,14.42-13.16c0,0-10.01,11.2-15.44,13.33   c0,0,10.51,1.84,16.37,6.77"/>
      <path className={styles.pl4} cus-attr='plLf2' style={{transformOrigin: '28.01% 31.47%'}} d="M192.05,164.81c0,0,20,1.12,19.07,10.23c-0.93,9.12,2.51,6.23,1.77,10.88c-0.74,4.65-10.98,10.14-20.09,9.58   s-24.44-11.56-24.44-11.56L192.05,164.81z"/>
      <path className={styles.pl4} cus-attr='plLf2' style={{transformOrigin: '27.77% 30.93%'}} d="M166.61,185.57c0,0,16.6-27.19,22.19-27.47c5.58-0.28,14.14,16.56-21.21,27.26c0,0,24.19-5.12,30.33,8.19   c6.14,13.3,6.33,11.16,6.51,12.65c0.19,1.49-10.42,1.77-18.33,0.65C178.19,205.74,173.1,183.36,166.61,185.57z"/>
    </g>
  </svg>
}
const Leaf = ({}: {}) => {
  return <svg version="1.1" 
    viewBox={"0 0 300 300"}
    style={{
      width: '100%',
      height: '100%'
    }}
  >
    <g>
      <path className={styles.lf1} d="M205.52,123.45c4.09,5.91,18.65,48.71,0,67.8s-46.4-1.84-69.14,35.92c0,0-1.36-27.42-6.37-38.05   c-5-10.63,4.09-45.65,48.67-58.39C201.43,123.45,205.52,123.45,205.52,123.45z"/>
      <path className={styles.lf2} d="M204.36,126.73c1.3,10.83,1.92,29.89-10.49,34.44c-8.86,2.77-18.1,4.58-26.11,9.44c-11.44,6.68-18.81,18.49-23.12,30.77    c4.11-12.38,11.39-24.42,22.79-31.32c7.49-4.7,16.22-6.81,24.54-9.41c13.15-3.39,12.17-22.97,10.71-33.65    C202.69,127.01,204.36,126.73,204.36,126.73L204.36,126.73z"/>
      <path className={styles.lf2} d="M153.61,183.91c2.13,3.99,2.52,8.51,2.34,12.93c-0.09-1.08-0.21-2.15-0.4-3.21c-0.55-3.03-1.52-6.25-3.32-8.73    C152.23,184.9,153.61,183.91,153.61,183.91L153.61,183.91z"/>
      <path className={styles.lf2} d="M149.6,190.86c-2.64-1.35-5.75-2.05-8.73-1.69c3.06-0.95,6.34-0.79,9.41,0.13C150.29,189.3,149.6,190.86,149.6,190.86    L149.6,190.86z"/>
      <path className={styles.lf2} d="M156.96,179.03c-2.61-3.06-6.87-4.6-10.86-4.68c-0.6-0.01-1.2,0.02-1.8,0.03c2.41-0.42,4.87-0.46,7.27,0.09    c2.49,0.6,4.76,1.64,6.69,3.45C158.25,177.93,156.96,179.03,156.96,179.03L156.96,179.03z"/>
      <path className={styles.lf2} d="M163.65,173.13c2.8,5.78,4.85,12.11,4.78,18.56c-0.22-3.19-1.03-6.28-2.13-9.24c-1.11-2.92-2.49-5.82-4.12-8.46    C162.18,173.98,163.65,173.13,163.65,173.13L163.65,173.13z"/>
      <path className={styles.lf2} d="M166.6,170.8c-4.08-6.35-13.75-8.28-20.77-9.33c6.02,0.42,12.22,1.33,17.55,4.34c1.86,1.1,3.62,2.36,4.76,4.28    C168.14,170.09,166.6,170.8,166.6,170.8L166.6,170.8z"/>
      <path className={styles.lf2} d="M175.17,166.37c3.43,6.93,4.06,14.88,4.29,22.49c0,0-0.29-2.83-0.29-2.83c-0.59-4.64-1.49-9.38-3.09-13.77    c-0.63-1.68-1.38-3.49-2.33-4.96C173.74,167.3,175.17,166.37,175.17,166.37L175.17,166.37z"/>
      <path className={styles.lf2} d="M188.72,162.06c2.55,7.66,2.88,15.7,3.08,23.69c-0.34-3.94-0.8-7.87-1.52-11.75c-0.71-3.77-1.59-7.76-3.11-11.23    C187.17,162.77,188.72,162.06,188.72,162.06L188.72,162.06z"/>
      <path className={styles.lf2} d="M180.59,164.74c-3.02-5.81-6.88-12.15-13.22-14.71c1.65,0.44,3.19,1.26,4.61,2.24c4.22,3.05,7.43,7.26,10.12,11.69    C182.1,163.96,180.59,164.74,180.59,164.74L180.59,164.74z"/>
      <path className={styles.lf2} d="M192.92,160.77c-0.86-5.77-2.75-11.81-6.97-16.04c1.16,0.95,2.21,2.05,3.14,3.26c2.72,3.72,4.46,8.03,5.52,12.51    C194.6,160.5,192.92,160.77,192.92,160.77L192.92,160.77z"/>
    </g>
  </svg>
}
const Flower1 = ({}: {}) => {
  return <svg version="1.1" 
    viewBox={"0 0 300 300"}
    style={{
      width: '100%',
      height: '100%'
    }}
  >
    <path className={styles.lf1} d="M197.08,100.39c4.84-12.84,3.35-31.63,44.47-37.95c0,0,0,28.28-9.3,37.95s-29.16,11.07-29.16,11.07   s12.6-9.3,16.23-18.51c0,0-7.83,11.56-14.98,16.37C195.78,115.09,197.08,100.39,197.08,100.39z"/>
    <path className={styles.flw1_a} d="M155.97,138.06c0,0-1.67-6.6,7.63-19.81c9.3-13.21,24.74-23.38,34.6-26.76s23.07-4.54,13.02,11.2   s-38.33,35.37-50.98,37.46c0,0,19.91-5.44,43.91-27.68c9.86-8.65,34.98-6.7,36.09-5.21s4.74,8.93-8.74,15.26   c-13.49,6.33-33.58,8.74-41.49,11.53s-27.91,10.33-27.91,10.33s38.23-16.74,60.46-16.74s26.88,5.4,11.81,14.42   c-15.07,9.02-22.6,6.14-39.72,4.65s-32.84,3.35-32.84,3.35s21.3-7.91,54.05,0c24.56,6.6,26.7,15.16,14.98,18.7   c-11.72,3.53-25.67,6.14-37.86,1.21c-12.19-4.93-16-10.79-32.56-14.33c0,0,34.05,8.47,52,26.79c17.95,18.33,21.67,28.28,5.86,25.77   c-15.81-2.51-21.49-7.16-32.93-22.14c-11.44-14.98-22.98-23.53-26.88-27.81c0,0,31.44,26.98,38.05,45.3   c6.6,18.33,3.44,29.67-12.93,13.02c-13.4-14.51-20.37-27.07-22.6-32.93c0,0-1.86-15.91-6.7-21.4c0,0,12.65,16.19,5.49,66.05   c0,0-3.26,14.23-11.07,7.44c0,0-1.58-1.02-3.07-15.53s-3.91-36.65,4.37-59.63c0,0-4.09,17.21-7.07,34.7s-20.09,26.14-22.33,25.77   c-2.23-0.37-8.18-30.45,10.33-44.65s10.23-20.37,10.23-20.37s3.63,9.58-8.37,18.05s-13.83,13.99-40.47,14.14   s2.98-18.42,19.53-23.63s24.19-11.16,26.42-15.07c0,0-14.62,21.4-57.45,9.12c-27.25-7.81-5.99-15.63,2.75-16s24.93-7.26,53.58,0.93   c0,0-37.02-10.49-49.45-10.32s-25.71-8.66-3.38-12.93s26.98,0.86,37.21,6.85c10.23,5.99,22.14,12.5,22.14,12.5   s-24.37-12.49-42.79-26.52c-10.51-19.06,2.98-17.57,15.63-12.73s18.05,15.67,20.84,21.98c2.79,6.3,8.93,17.28,8.93,17.28   s-14.51-18.15-10.23-46.29c2.6-14.74,15.26-11.39,19.91,5.73s-4.55,39.43-4.55,39.43s9.02-27.89,4.93-42.78   c0,0,13.02-28.28,20.65-29.77c3.16,0,2.42,5.02,2.42,5.02s12.65-8.26-0.93,30.38C178.48,101.38,159.5,115.82,155.97,138.06z"/>
    <ellipse className={styles.flw1_b} transform="matrix(0.967 -0.2546 0.2546 0.967 -32.9329 43.2985)" cx="150.79" cy="148.86" rx="13.96" ry="15.9"/>
  </svg>
}
const LoveTxt = ({}: {}) => {
  return <svg version="1.1" 
    viewBox={"0 0 260 70"}
    style={{
      width: '100%',
      height: '100%'
    }}
  >
    <g>
      <path className={styles.lvt} cus-attr='lvTxt' d="M11.6,13.5c0,0,1.2,11.1,0,21c-0.4,3.4-0.7,11.4,0.2,11.8c2,0.9,7.6-3.5,9.4-5.9"/>
      <path className={styles.lvt} cus-attr='lvTxt' d="M33.2,27.3C30,26.6,23,42.5,27.9,46.3C32.7,50,44,40,41.2,31c-2.8-9-11.1-6.9-9.1-3.2"/>
      <path className={styles.lvt} cus-attr='lvTxt' d="M45.8,25.8c0.6,0.5,5,8.8,7.3,17.5c0.9,2.6,1.6,2.9,2.3,2.9s9-10.1,14.1-25.2"/>
      <path className={styles.lvt} cus-attr='lvTxt' d="M73.7,30.1c0.6,2.2,3.3,6.8,9.4,0.4c6.1-6.4-0.7-10.8-4.7-5.9c-3.3,4-9.3,20.5-1.7,23c6.3,1.1,10-5.5,10-5.5"/>
      <path className={styles.lvt} cus-attr='lvTxt' d="M103,29.3c0.5,0.8,1.7,1.8,20.6,0"/>
      <path className={styles.lvt} cus-attr='lvTxt' d="M126.8,13.7c-1-3.5-7.4-8.7-11.4,3.5c-4.1,12.2-5.4,32.3-2.1,43.4"/>
      <path className={styles.lvt} cus-attr='lvTxt' d="M133.6,27.4c-1-0.4-6.9,3.1-6.3,17c0.4,5.8,12.2,2.2,15.1-8.1c2-10.7-9.4-14-10.1-8.9"/>
      <path className={styles.lvt} cus-attr='lvTxt' d="M149.6,24.8c0.5,0.7,1.9,13.8,1.5,21.4c0,0-0.8-15.8,14.7-20.7"/>
      <path className={styles.lvt} cus-attr='lvTxt' d="M169.2,30c0.9,3.9,5.6,6.8,10.6-1.4c3.1-6-4.4-8.9-8.3,0.4s-4,17.2,0.9,18.1c4.8,0.9,8.7-2.2,10-4.9"/>
      <path className={styles.lvt} cus-attr='lvTxt' d="M185.7,26c1.7,1.7,4.6,6.8,7.4,16.7c1.1,4.1,2.2,4.5,5,0.4s7.1-11,11.5-22.2"/>
      <path className={styles.lvt} cus-attr='lvTxt' d="M213.6,29.8c0,0,1,7.2,6.9,2.7s5.4-8.8,2.5-9.9c-2.9-1-8.2,4.7-10,17.1c-1.7,12.4,11.1,7.9,13.7,2.5"/>
      <path className={styles.lvt} cus-attr='lvTxt' d="M233.1,24.8c1,1.6,2.2,14.9,1.5,21.1c0,0,0.7-17,14.9-20.4"/>
    </g>
  </svg>
}
const Star = ({ color = '#fff' }: { color?: string }) => {
  const width = 20;
  const half = 10; //width/2;
  const quat = 5; //width/4;
  return (
    <svg
      version="1.1"
      viewBox={'0 0 ' + width + ' ' + width + ''}
      height={width}
      width={width}
      style={{
        width: '100%',
        height: '100%',
      }}
    >
      <path
        d={'M 0 '+half+' c '+quat+' 0 '+half+' -'+quat+' '+half+' -'+half+' c 0 '+quat+' '+quat+' '+half+' '+half+' '+half+' c -'+quat+' 0 -'+half+' '+quat+' -'+half+' '+half+' c 0 -'+quat+' -'+quat+' -'+half+' -'+half+' -'+half+''}
        className={styles.star}
      />
    </svg>
  );
};
interface ViewProps extends React.HTMLAttributes<HTMLSpanElement> {
}
interface States {
  activeState?: boolean
  coloredState?: boolean
}
export default class ButtonDayNight extends React.Component<ViewProps, States> {
  public state: States = {

  }
  public componentDidMount(): void {
    this.init()
    // this.changeState()
  }
  public render() {
    const { className, children, ...restProps } = this.props;
    const { activeState, coloredState } = this.state
    return (
      <div className={cx(styles.button, {
        [styles.active]: activeState,
        [styles.colored]: coloredState
      }, className)} {...restProps} >
        <div className={styles.btnInner}>
          <Moon />
          <div className={cx(styles.abBox, styles.plants)}>
            <Plants />
          </div>
          <div className={cx(styles.abBox, styles.leaf)}>
            <Leaf />
          </div>
          <div className={cx(styles.abBox, styles.flower1)}>
            <Flower1 />
          </div>
          <div className={cx(styles.abBox, styles.flower2)}>
            <Flower1 />
          </div>
          <div className={cx(styles.abBox, styles.flower3)}>
            <Flower1 />
          </div>
          <div className={cx(styles.abBox, styles.flower4)}>
            <Flower1 />
          </div>
          {new Array(4).fill(1).map((e, ind) => (
            <span
              className={cx(styles.abBox, styles['star' + (ind + 1)])}
              key={ind + 'star'}
            >
              <Star />
            </span>
          ))}
          <div className={cx(styles.abBox, styles.txts)}>
            <div className={styles.name}>
              <span className={styles.txt}>G</span>
              <span className={styles.txt}>&</span>
              <span className={styles.txt}>Z</span>
            </div>
            <div className={styles.time}>
              <span className={styles.txt}>2</span>
              <span className={styles.txt}>0</span>
              <span className={styles.txt}>2</span>
              <span className={styles.txt}>
                <span className={styles.t1}>0</span>
                <span className={styles.t2}>3</span>
              </span>
              <span className={styles.txt}>.</span>
              <span className={styles.txt}>5</span>
              <span className={styles.txt}>.</span>
              <span className={styles.txt}>2</span>
              <span className={styles.txt}>0</span>
            </div>
            <div className={styles.loveTxt}>
              <LoveTxt />
            </div>
          </div>
        </div>
        <div className={styles.startBox} onClick={this.changeState}>
          <ButtonStart />  
          <div className={styles.fakeBtn}></div>
        </div>
      </div>
    );
  }
  private init = () => {
    this.hideAllPath()
    this.leafHide('[cus-attr="plLf"]')
    this.leafHide('[cus-attr="plLf2"]')
  }
  private changeState = () => {
    const { activeState } = this.state
    if(activeState) {
      this.hideAllPath();
      this.leafHide('[cus-attr="plLf"]')
      this.leafHide('[cus-attr="plLf2"]')
      this.changeColor(false)
    }else {
      const moonTime = 3;
      this.pathsAnimate('#plAn1', {delayBase: moonTime+0.1})
      this.pathsAnimate('#plAn2', {duration: 6, delayBase: moonTime})
      this.leafAnimate('[cus-attr="plLf"]', {delayBase: moonTime+1})
      this.leafAnimate('[cus-attr="plLf2"]', {delayBase: moonTime})
      this.pathsAnimate('[cus-attr="lvTxt"]', {delayBase: moonTime+5.5, duration: 0.2, delayStep: 0.3})
      this.changeColor(true)
    }
    this.setState({activeState: !this.state.activeState})
  }
  private colorTimeout:any = null
  private changeColor = (state:boolean) => {
    if(state) {
      if(this.colorTimeout) {clearTimeout(this.colorTimeout)}
      this.colorTimeout = setTimeout(() => {
        this.setState({
          coloredState: true
        })
      }, 12000)
    }else {
      this.setState({
        coloredState: false
      })
    }
  }
  private pathsAnimate = (query:string, params: {
    duration?: number
    delayBase?: number
    delayStep?: number
  } = {}) => {
    const paths:any = document.querySelectorAll(query);
    paths.forEach((path,i,obj) => {
      if(!path.style.strokeDashoffset) {
        const length = path.getTotalLength();
        path.style.transition = path.style.WebkitTransition = 'none';
        path.style.strokeDasharray = length + ' ' + length;
        path.style.strokeDashoffset = length;
      }
      path.getBoundingClientRect();
      path.style.transition = path.style.WebkitTransition = 'stroke-dashoffset '+(params.duration || 4)+'s ease-out';
      path.style.transitionDelay = path.style.WebkitTransitionDelay = (i*(params.delayStep || 0.6)+(params.delayBase || 0))+'s';
      path.style.strokeDashoffset = '0';
    })
  }
  private hideAllPath = () => {
    const queryList = ['#plAn1', '#plAn2'];
    queryList.map(e => {
      this.pathsHide(e)
    })
    this.pathsHide('[cus-attr="lvTxt"]')
  }
  private pathsHide = (query:string) => {
    const paths:any = document.querySelectorAll(query);
    paths.forEach((path,i,obj) => {
      const length = path.getTotalLength();
      path.style.transition = path.style.WebkitTransition = 'none';
      path.style.strokeDasharray = length + ' ' + length;
      path.style.strokeDashoffset = length;
    })
  }
  private leafHide = (query:string) => {
    const leaves:any = document.querySelectorAll(query);
    leaves.forEach((item,i,obj) => {
      item.style.transition = item.style.WebkitTransition = 'none';
      item.style.transform = 'scale(0)';
    })
  }
  private leafAnimate = (query:string, params: {
    duration?: number
    delayBase?: number
  } = {}) => {
    const leaves:any = document.querySelectorAll(query);
    leaves.forEach((item,i,obj) => {
      item.style.transition = item.style.WebkitTransition = 'none';
      item.style.transform = 'scale(0)';
      item.getBoundingClientRect();
      item.style.transition = item.style.WebkitTransition = 'transform '+(params.duration || 1)+'s ease-out';
      item.style.transitionDelay = item.style.WebkitTransitionDelay = (i*0.6+(params.delayBase || 0))+'s';
      item.style.transform = 'scale(1)';
    })
  }
}

Less:

@bgCo: #f0f2f5;
@bk: #000;
@startW: 160px;
@timeHover: 0.5s;
@timeActive: 0.8s;
@mainW: 300px;
@keyframes heartAnimate {
  0% {
    stroke-dasharray: 215, 215;
	  stroke-dashoffset: 0;
  }
  50% {
    stroke-dasharray: 330, 100;
    stroke-dashoffset: -100;
  }
  100% {
    stroke-dasharray: 215, 215;
    stroke-dashoffset: -430;
  }
}
@keyframes heartAnimate2 {
  from {
    stroke-dasharray: 430, 430;
    stroke-dashoffset: 0;
  }
  to {
    stroke-dasharray: 430, 430;
    stroke-dashoffset: 430;
  }
}
.button {
  display: flex;
  flex-direction: column;
  align-items: center;
  line-height: 0;
  position: relative;
  padding: 100px 0;
}
.startBox {
  display: inline-block;
  width: @startW;
  position: relative;
  cursor: pointer;
  .fakeBtn {
    position: absolute;
    width: 97%;
    height: 92%;
    top: 4%;
    left: 1.5%;
    border: solid 1px transparent;
    border-radius: @startW * 0.08;
    transition: all @timeHover ease-in-out;
  }
}
.buttonBorder {
  stroke: #67abee;
  stroke-dasharray: 1544, 1544;
  stroke-dashoffset: 0;
  transition: all @timeActive ease-in-out;
}
.heartOuter {
  transform-origin: 50% 50%;
  transition: all @timeHover * 0.8 ease-in-out;
  transition-delay: @timeHover * 0.7;
  .heart {
    stroke-dasharray: 430, 430;
    stroke-dashoffset: 430;
    stroke: #3e60f3;
    animation: heartAnimate 1s infinite;
    animation-timing-function: linear;
  }
}
.start {
  stroke: #3e60f3;
  stroke-dasharray: 220, 220;
  stroke-dashoffset: 220;
  transition: all @timeHover * 1.3 ease-in-out;
  transition-delay: 0s;
}
.btnInner {
  display: inline-block;
  position: relative;
  top: 3px;
  z-index: 1;
  width: @mainW;
  height: @mainW;
  opacity: 0;
  .moon {
    stroke: @bk;
    fill: @bgCo;
    stroke-width: 3;
    stroke-dasharray: 2355, 2355;
    stroke-dashoffset: 2355;
  }
  .star {
    stroke: @bk;
    fill: @bgCo;
    stroke-width: 1;
    transform-origin: center;
  }
  .lf1 {
    fill: @bgCo;
    stroke: @bk;
    stroke-width: 2;
    stroke-miterlimit: 10;
  }
  .lf2 {
    fill: @bgCo;
    stroke: @bk;
    stroke-width: 1.3;
    stroke-miterlimit: 0;
  }
  .flw1_a {
    fill: @bgCo;
    stroke: @bk;
    stroke-width: 3;
  }
  .flw1_b {
    fill: @bk;
    stroke: @bk;
  }
  .pl2 {
    fill: none;
    stroke: @bk;
    stroke-width: 2.2677;
    stroke-miterlimit: 10;
  }
  .pl3 {
    fill: none;
    stroke: @bk;
    stroke-miterlimit: 10;
  }
  .pl4 {
    fill: #FFFFFF;
    stroke: @bk;
    stroke-miterlimit: 10;
  }
  .lvt {
    fill: none;
    stroke: @bk;
    stroke-width: 1.7;
  }
  .abBox {
    position: absolute;
    &.plants {
      width: 100%;
      top: 0;
      left: 0;
    }
    &.leaf {
      width: 60%;
      top: 58%;
      left: -8%;
      transform: scale(0);
    }
    &.flower1 {
      width: 55%;
      top: 60%;
      left: 30%;
      transform: scale(0);
    }
    &.flower2 {
      width: 60%;
      top: 43%;
      left: -7%;
      transform: scale(0);
    }
    &.flower3 {
      width: 60%;
      top: 28%;
      left: 2%;
      transform: scale(0);
    }
    &.flower4 {
      width: 60%;
      top: 52%;
      left: 12%;
      transform: scale(0);
    }
    &.star1 {
      width: 2.6%;
      left: 27%; top: 37%;
      transform: scale(0);
    }
    &.star2 {
      width: 2%;
      left: 41%; top: 22%;
      transform: scale(0);
    }
    &.star3 {
      width: 2.5%;
      left: 50%; top: 17%;
      transform: scale(0);
    }
    &.star4 {
      width: 3.5%;
      left: 34%; top: 21%;
      transform: scale(0);
    }
    &.txts {
      top: 32%;
      left: 55%;
      display: flex;
      flex-direction: column;
      align-items: center;
      .name {
        display: flex;
        align-items: center;
        .txt {
          font-size: 22px;
          line-height: 1;
          letter-spacing: 20px;
          opacity: 0;
        }
      }
      .time {
        display: flex;
        align-items: center;
        color: #999;
        .txt {
          font-size: 12px;
          line-height: 1;
          letter-spacing: 1px;
          transform: rotateX(90deg);
          position: relative;
          display: inline-block;
        }
        .t1 {
          display: inline-block;
          position: relative;
          backface-visibility: hidden;
          transform: rotateX(0deg);
        }
        .t2 {
          display: inline-block;
          backface-visibility: hidden;
          position: absolute;
          top: 0;
          left: 0;
          transform: rotateX(180deg);
        }
      }
    }
  }
}
.button {
  .startBox {
    &:hover {
      .heartOuter {
        transition-delay: 0s;
        transform: scale(0.8) translate(-35%,0px);
        .heart {
          
        }
      }
      .start {
        stroke-dashoffset: 0;
        transition-delay: @timeHover * 0.5;
      }
      .fakeBtn {
        box-shadow: 0 0 10px rgba(106,140,198,0.8);
      }
    }
  }
  &.active {
    .startBox {
      .heartOuter {
        .heart {
          animation: heartAnimate2 @timeActive 1;
        }
      }
      .start {
        stroke-dashoffset: 220;
        transition: all @timeActive ease-in-out;
      }
      .fakeBtn {
        box-shadow: 0 0 0 transparent;
      }
    }
    .buttonBorder {
      stroke-dashoffset: 1544;
      transition-delay: @timeActive;
    }
    .btnInner {
      opacity: 1;
      transition: opacity @timeHover ease-in-out;
      .moon {
        stroke-dashoffset: 4710;
        transition: all @timeActive * 1.5 ease-in-out;
        transition-delay: @timeActive * 1.9;
      }
      .abBox {
        transition: all @timeActive * 2 ease-in-out;
        &.leaf {
          transform: scale(1);
          transition-delay: @timeActive * 2 + 2.1;
        }
        &.flower1 {
          transform: scale(1);
          transition-delay: @timeActive * 2 + 1.3;
        }
        &.flower2 {
          transform: scale(1);
          transition-delay: @timeActive * 2 + 1.6;
        }
        &.flower3 {
          transform: scale(1);
          transition-delay: @timeActive * 2 + 1.9;
        }
        &.flower4 {
          transform: scale(1);
          transition-delay: @timeActive * 2 + 1;
        }
        &.star1 {
          transition: all 0.6s ease-in-out;
          transition-delay: @timeActive * 6;
          transform: scale(1);
        }
        &.star2 {
          transition: all 0.6s ease-in-out;
          transition-delay: @timeActive * 6 + 0.2s;
          transform: scale(1);
        }
        &.star3 {
          transition: all 0.6s ease-in-out;
          transition-delay: @timeActive * 6 + 0.4s;
          transform: scale(1);
        }
        &.star4 {
          transition: all 0.6s ease-in-out;
          transition-delay: @timeActive * 6 + 0.6s;
          transform: scale(1);
        }
        &.txts {
          .name {
            .txt {
              letter-spacing: 5px;
              transition: all 3s ease-in-out;
              transition-delay: 5s;
              opacity: 1;
            }
          }
          .time {
            perspective: 100px;
            transform-style: preserve-3d;
            each(range(9), {
              .txt:nth-child(@{value}) {
                transition: all 1.8s ease-in-out;
                transition-delay: @value * 0.22s + 6s;
                transform: rotateX(0deg);
              }
            });
            .t1 {
              transition: all 1s ease-in-out;
              transition-delay: 9.6s;
              transform: rotateX(180deg);
            }
            .t2 {
              transition: all 1s ease-in-out;
              transition-delay: 9.6s;
              transform: rotateX(0deg);
            }
          }
        }
      }
    }
  }
  &.colored {
    .btnInner {
      .moon {
        stroke: #ffe770;
        fill: #fffdc7;
        transition-property: stroke, fill;
        transition-duration: 0.6s;
        transition-delay: 0.2s;
      }
      .star {
        stroke: #ffac00;
        fill: #ffac00;
        transition-property: stroke, fill;
        transition-duration: 0.6s;
        transition-delay: 0.6s;
      }
      .lf1 {
        fill: #e3ffd3;
        stroke: #88b680;
        transition-property: stroke, fill;
        transition-duration: 0.6s;
        transition-delay: 0.85s;
      }
      .lf2 {
        fill: none;
        stroke: #88b680;
        transition-property: stroke, fill;
        transition-duration: 0.6s;
        transition-delay: 0.9s;
      }
      .flw1_a {
        fill: #fee5be;
        stroke: #ffc679;
        transition-property: stroke, fill;
        transition-duration: 0.6s;
        transition-delay: 0.4s;
      }
      .flw1_b {
        fill: #ffc679;
        stroke: #ffc679;
        transition-property: stroke, fill;
        transition-duration: 0.6s;
        transition-delay: 0.5s;
      }
      .pl2 {
        stroke: #e93434;
        transition-property: stroke, fill !important;
        transition-duration: 0.6s !important;
        transition-delay: 1.4s !important;
      }
      .pl3 {
        stroke: #e93434;
        transition-property: stroke, fill !important;
        transition-duration: 0.6s !important;
        transition-delay: 1.6s !important;
      }
      .pl4 {
        fill: #ffd7db;
        stroke: #e93434;
        transition-property: stroke, fill !important;
        transition-duration: 0.6s !important;
        transition-delay: 1.7s !important;
      }
      .lvt {
        stroke: #953723;
        transition-property: stroke, fill !important;
        transition-duration: 0.9s !important;
        transition-delay: 0s !important;
      }
      .abBox {
        &.txts {
          .name {
            .txt {
              color: #883523;
              transition-property: color;
              transition-duration: 0.2s;
              transition-delay: 0s;
            }
          }
        }
      }
    }
  }
}

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值