Ver código fonte

feat: 金额统计动画 90%

wangjiacheng 3 anos atrás
pai
commit
56f58112b9
5 arquivos alterados com 511 adições e 37 exclusões
  1. 0 2
      package.json
  2. 117 0
      src/views/total-sum/fr.scss
  3. 73 12
      src/views/total-sum/index.vue
  4. 321 0
      src/views/total-sum/mixin.js
  5. 0 23
      yarn.lock

+ 0 - 2
package.json

@@ -11,7 +11,6 @@
     "test:unit": "vue-cli-service test:unit"
   },
   "dependencies": {
-    "animated-number-vue": "^1.0.0",
     "axios": "^0.19.0",
     "babel-polyfill": "^6.26.0",
     "core-js": "^2.6.5",
@@ -21,7 +20,6 @@
     "reset.css": "^2.0.2",
     "vue": "^2.6.10",
     "vue-count-to": "^1.0.13",
-    "vue-flip-number": "^1.1.1",
     "vue-router": "^3.0.3",
     "vue-seamless-scroll": "^1.1.17",
     "vuex": "^3.0.1"

+ 117 - 0
src/views/total-sum/fr.scss

@@ -0,0 +1,117 @@
+$particles: 50;
+$width: 500;
+$height: 500;
+
+// Create the explosion...
+$box-shadow: ();
+$box-shadow2: ();
+@for $i from 0 through $particles {
+  $box-shadow: $box-shadow,
+               random($width)-$width / 2 + px
+               random($height)-$height / 1.2 + px
+               hsl(random(360), 100, 50);
+  $box-shadow2: $box-shadow2, 0 0 #fff
+}
+@mixin keyframes ($animationName) {
+    @-webkit-keyframes #{$animationName} {
+        @content;
+    }
+
+    @-moz-keyframes #{$animationName} {
+        @content;
+    }
+
+    @-o-keyframes #{$animationName} {
+        @content;
+    }
+
+    @-ms-keyframes #{$animationName} {
+        @content;
+    }
+
+    @keyframes #{$animationName} {
+        @content;
+    }
+}
+
+@mixin animation-delay ($settings) {
+    -moz-animation-delay: $settings;
+    -webkit-animation-delay: $settings;
+    -o-animation-delay: $settings;
+    -ms-animation-delay: $settings;
+    animation-delay: $settings;
+}
+
+@mixin animation-duration ($settings) {
+    -moz-animation-duration: $settings;
+    -webkit-animation-duration: $settings;
+    -o-animation-duration: $settings;
+    -ms-animation-duration: $settings;
+    animation-duration: $settings;
+}
+
+@mixin animation ($settings) {
+    -moz-animation: $settings;
+    -webkit-animation: $settings;
+    -o-animation: $settings;
+    -ms-animation: $settings;
+    animation: $settings;
+}
+
+@mixin transform ($settings) {
+    transform: $settings;
+    -moz-transform: $settings;
+    -webkit-transform: $settings;
+    -o-transform: $settings;
+    -ms-transform: $settings;
+}
+
+.pyro > .before, .pyro > .after {
+  position: absolute;
+  width: 5px;
+  height: 5px;
+  border-radius: 50%;
+  box-shadow: $box-shadow2;
+  @include animation((1s bang ease-out infinite backwards, 1s gravity ease-in infinite backwards, 5s position linear infinite backwards));
+}
+    
+.pyro > .after {
+  @include animation-delay((1.25s, 1.25s, 1.25s));
+  @include animation-duration((1.25s, 1.25s, 6.25s));
+}
+        
+@include keyframes(bang) {
+  to {
+    box-shadow:$box-shadow;
+  }
+}
+    
+@include keyframes(gravity)  {
+  to {
+    @include transform(translateY(200px));
+    opacity: 0;
+  }
+}
+    
+@include keyframes(position) {
+  0%, 19.9% {
+    margin-top: 10%;
+    margin-left: 40%;
+  }
+  20%, 39.9% {
+    margin-top: 40%;
+    margin-left: 30%;
+  }
+  40%, 59.9% {  
+    margin-top: 20%;
+    margin-left: 70%
+  }
+  60%, 79.9% {  
+    margin-top: 30%;
+    margin-left: 20%;
+  }
+  80%, 99.9% {  
+    margin-top: 30%;
+    margin-left: 80%;
+  }
+}

+ 73 - 12
src/views/total-sum/index.vue

@@ -2,24 +2,24 @@
  * @Author: wangjiacheng
  * @Date: 2021-10-14 11:57:19
  * @LastEditors: wangjiacheng
- * @LastEditTime: 2021-10-14 22:00:18
+ * @LastEditTime: 2021-10-15 14:54:51
  * @Description:
 -->
 <template>
   <div class="total-sum">
+    <!-- <img src="../../assets/images/total-sum-bg.png" class="img-bg" /> -->
+    <canvas id="canvas"></canvas>
     <div class="content">
       <div class="title">
         线上缴费累计金额
       </div>
-      <div class="sum">
-        <!-- <flip :deadline="moneny" :length="monenyLength"></flip> -->
+      <div :class="{ sum: true, 'sum-billion': isBillion }">
         <digit-roll
           v-model="moneny"
           :duration="1000"
           :delay="1000"
         >
         </digit-roll>
-        <!-- {{moneny}} -->
       </div>
     </div>
     <div class="footer">
@@ -31,14 +31,15 @@
 </template>
 
 <script>
-// import Flip from '@/components/flip'
 
 // import { totalSum } from '@/api'
+import mixin from './mixin.js'
 import wcLogo from '@/assets/images/wc.png'
 import huiguanjiaLogo from '@/assets/images/huiguanjia.png'
 
 export default {
   name: 'TotalSum',
+  mixins: [mixin],
   components: {
     // Flip
   },
@@ -46,7 +47,9 @@ export default {
     return {
       moneny: 99634580.96,
       monenyLength: 0,
-      timer: null
+      timer: null,
+      showFire: false,
+      isBillion: false
     }
   },
   computed: {
@@ -57,12 +60,31 @@ export default {
       return huiguanjiaLogo
     }
   },
+  watch: {
+    moneny (nVal) {
+      if (nVal >= 1e8) {
+        // this.showFire = true
+        setTimeout(() => {
+          // this.fireworks()
+          // this.fireworkss()
+          this.isBillion = true
+        }, 300)
+      }
+    }
+    // showFire (nVal) {
+    //   if (nVal) {
+    //     setTimeout(() => {
+    //       this.showFire = false
+    //     }, 2000)
+    //   }
+    // }
+  },
   methods: {
     getTotalSum () {
       this.timer = setInterval(() => {
-        const n = this.moneny + Math.floor(Math.random() * 100000)
+        const n = this.moneny + Math.floor(Math.random() * 1000000)
         this.moneny = n
-        this.monenyLength = `${n.toLocaleString('hanidec')}`.length
+        // this.monenyLength = `${n.toLocaleString('hanidec')}`.length
         // totalSum.getTotalSum().then(res => {
         //   if (res && res.data) {
         //     const data = Number(res.data.data)
@@ -78,25 +100,44 @@ export default {
   created () {
     this.getTotalSum()
   },
+  mounted () {
+    this.fireworkss()
+  },
   beforeDestroy () {
     clearInterval(this.timer)
   }
 }
 </script>
 
-<style lang="scss" scoped>
+<style lang="scss">
+  @import './fr.scss';
+
   @font-face {
     font-family: AIdrich-Regular;
     src: url('../../assets/css/Aldrich-Regular.ttf');
   }
 
+  #canvas {
+    top: 105px;
+    position: relative;
+    z-index: 100;
+  }
+
   .total-sum {
+    position: relative;
     text-align: center;
     height: 100%;
     background: url('../../assets/images/total-sum-bg.png');
     background-repeat: no-repeat;
     background-size: cover;
     .content {
+      position: absolute;
+      z-index: 1001;
+      left: 0;
+      top: 0;
+      right: 0;
+      bottom: 100px;
+      margin: auto;
       display: flex;
       flex-direction: column;
       justify-content: center;
@@ -104,15 +145,21 @@ export default {
     }
     .title {
       font-size: 58px;
-      color: rgb(255, 210, 132) !important;
+      color: rgb(255, 210, 132);
       margin-bottom: 50px;
       font-family: 'Source Han Sans CN';
     }
     .sum {
+      z-index: 1001;
       font-size: 11.25em;
-      color: rgb(255, 181,53) !important;
       font-family: 'AIdrich-Regular';
-      -webkit-box-reflect: below 0 linear-gradient(transparent,rgba(255, 255, 255, 0.3));
+      -webkit-box-reflect: below -30px linear-gradient(transparent,rgba(255, 255, 255, 0.4));
+      span {
+        background: linear-gradient(180deg, #e1bc7e 10%, #8a5510 70%);
+        background-clip: text;
+        -webkit-background-clip: text;
+        color: transparent;
+      }
     }
     .footer {
       position: fixed;
@@ -128,5 +175,19 @@ export default {
         height: 2em;
       }
     }
+    .sum-billion {
+      animation: billion 2s;
+    }
+    @keyframes billion {
+      0% {
+        transform: scale(1);
+      }
+      50% {
+        transform: scale(1.2);
+      }
+      75% {
+        transform: scale(1);
+      }
+    }
   }
 </style>

+ 321 - 0
src/views/total-sum/mixin.js

@@ -0,0 +1,321 @@
+/*
+ * @Author: wangjiacheng
+ * @Date: 2021-10-15 10:58:28
+ * @LastEditors: wangjiacheng
+ * @LastEditTime: 2021-10-15 14:17:38
+ * @Description:
+ */
+
+export default {
+  methods: {
+    /* eslint-disable */
+    fireworkss() {
+      // window.addEventListener("resize", resizeCanvas, false);
+      // window.addEventListener("DOMContentLoaded", onLoad, false);
+      onLoad()
+
+      window.requestAnimationFrame =
+        window.requestAnimationFrame ||
+        window.webkitRequestAnimationFrame ||
+        window.mozRequestAnimationFrame ||
+        window.oRequestAnimationFrame ||
+        window.msRequestAnimationFrame ||
+        function (callback) {
+          window.setTimeout(callback, 1000 / 60);
+        };
+
+      var canvas, ctx, w, h, particles = [], probability = 0.04,
+        xPoint, yPoint;
+      function onLoad() {
+        canvas = document.getElementById("canvas");
+        ctx = canvas.getContext("2d");
+        resizeCanvas();
+
+        window.requestAnimationFrame(updateWorld);
+      }
+
+      function resizeCanvas() {
+        if (!!canvas) {
+          w = canvas.width = window.innerWidth;
+          h = canvas.height = window.innerHeight;
+        }
+      }
+
+      function updateWorld() {
+        update();
+        paint();
+        window.requestAnimationFrame(updateWorld);
+      }
+
+      function update() {
+        if (particles.length < 500 && Math.random() < probability) {
+          createFirework();
+        }
+        var alive = [];
+        for (var i = 0; i < particles.length; i++) {
+          if (particles[i].move()) {
+            alive.push(particles[i]);
+          }
+        }
+        particles = alive;
+      }
+
+      function paint() {
+        ctx.globalCompositeOperation = 'source-over';
+        ctx.fillStyle = "rgba(0,0,0,0.2)";
+        ctx.fillRect(0, 0, w, h);
+        ctx.globalCompositeOperation = 'lighter';
+        for (var i = 0; i < particles.length; i++) {
+          particles[i].draw(ctx);
+        }
+      }
+
+      function createFirework() {
+        xPoint = Math.random() * (w - 200) + 100;
+        yPoint = Math.random() * (h - 200) + 100;
+        var nFire = Math.random() * 50 + 100;
+        var c = "rgb(" + (~~(Math.random() * 200 + 55)) + ","
+          + (~~(Math.random() * 200 + 55)) + "," + (~~(Math.random() * 200 + 55)) + ")";
+        for (var i = 0; i < nFire; i++) {
+          var particle = new Particle();
+          particle.color = c;
+          var vy = Math.sqrt(25 - particle.vx * particle.vx);
+          if (Math.abs(particle.vy) > vy) {
+            particle.vy = particle.vy > 0 ? vy : -vy;
+          }
+          particles.push(particle);
+        }
+      }
+
+      function Particle() {
+        this.w = this.h = Math.random() * 4 + 1;
+
+        this.x = xPoint - this.w / 2;
+        this.y = yPoint - this.h / 2;
+
+        this.vx = (Math.random() - 0.5) * 10;
+        this.vy = (Math.random() - 0.5) * 10;
+
+        this.alpha = Math.random() * .5 + .5;
+
+        this.color;
+      }
+
+      Particle.prototype = {
+        gravity: 0.05,
+        move: function () {
+          this.x += this.vx;
+          this.vy += this.gravity;
+          this.y += this.vy;
+          this.alpha -= 0.01;
+          if (this.x <= -this.w || this.x >= screen.width ||
+            this.y >= screen.height ||
+            this.alpha <= 0) {
+            return false;
+          }
+          return true;
+        },
+        draw: function (c) {
+          c.save();
+          c.beginPath();
+
+          c.translate(this.x + this.w / 2, this.y + this.h / 2);
+          c.arc(0, 0, this.w, 0, Math.PI * 2);
+          c.fillStyle = this.color;
+          c.globalAlpha = this.alpha;
+
+          c.closePath();
+          c.fill();
+          c.restore();
+        }
+      }
+    },
+    fireworks() {
+      var _createClass = function () {
+        function defineProperties(target, props) {
+          for (var i = 0; i < props.length; i++) {
+            var descriptor = props[i];
+            descriptor.enumerable = descriptor.enumerable || false;
+            descriptor.configurable = true;
+            if ("value" in descriptor) descriptor.writable = true;
+            Object.defineProperty(target, descriptor.key, descriptor);
+          }
+        }
+
+        return function (Constructor, protoProps, staticProps) {
+          if (protoProps) defineProperties(Constructor.prototype, protoProps);
+          if (staticProps) defineProperties(Constructor, staticProps);
+          return Constructor;
+        };
+      }();
+
+      function _classCallCheck(instance, Constructor) {
+        if (!(instance instanceof Constructor)) {
+          throw new TypeError("Cannot call a class as a function");
+        }
+      }
+
+      var Progress = function () {
+        function Progress() {
+          var param = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
+
+          _classCallCheck(this, Progress);
+
+          this.timestamp = null;
+          this.duration = param.duration || Progress.CONST.DURATION;
+          this.progress = 0;
+          this.delta = 0;
+          this.progress = 0;
+          this.isLoop = !!param.isLoop;
+
+          this.reset();
+        }
+
+        Progress.prototype.reset = function reset() {
+          this.timestamp = null;
+        };
+
+        Progress.prototype.start = function start(now) {
+          this.timestamp = now;
+        };
+
+        Progress.prototype.tick = function tick(now) {
+          if (this.timestamp) {
+            this.delta = now - this.timestamp;
+            this.progress = Math.min(this.delta / this.duration, 1);
+
+            if (this.progress >= 1 && this.isLoop) {
+              this.start(now);
+            }
+
+            return this.progress;
+          } else {
+            return 0;
+          }
+        };
+
+        _createClass(Progress, null, [{
+          key: "CONST",
+          get: function get() {
+            return {
+              DURATION: 1000
+            };
+          }
+        }]);
+
+        return Progress;
+      }();
+
+      var Confetti = function () {
+        function Confetti(param) {
+          _classCallCheck(this, Confetti);
+
+          this.parent = param.elm || document.body;
+          this.canvas = document.createElement("canvas");
+          this.ctx = this.canvas.getContext("2d");
+          this.width = param.width || this.parent.offsetWidth;
+          this.height = param.height || this.parent.offsetHeight;
+          this.length = param.length || Confetti.CONST.PAPER_LENGTH;
+          this.yRange = param.yRange || this.height * 2;
+          this.progress = new Progress({
+            duration: param.duration,
+            isLoop: true
+          });
+          this.rotationRange = typeof param.rotationLength === "number" ? param.rotationRange : 10;
+          this.speedRange = typeof param.speedRange === "number" ? param.speedRange : 10;
+          this.sprites = [];
+
+          this.canvas.style.cssText = ["display: block", "position: absolute", "top: 0", "left: 0", "pointer-events: none"].join(";");
+
+          this.render = this.render.bind(this);
+
+          this.build();
+
+          this.parent.append(this.canvas);
+          this.progress.start(performance.now());
+
+          requestAnimationFrame(this.render);
+        }
+
+        Confetti.prototype.build = function build() {
+          for (var i = 0; i < this.length; ++i) {
+            var canvas = document.createElement("canvas"),
+              ctx = canvas.getContext("2d");
+
+            canvas.width = Confetti.CONST.SPRITE_WIDTH;
+            canvas.height = Confetti.CONST.SPRITE_HEIGHT;
+
+            canvas.position = {
+              initX: Math.random() * this.width,
+              initY: -canvas.height - Math.random() * this.yRange
+            };
+
+            canvas.rotation = this.rotationRange / 2 - Math.random() * this.rotationRange;
+            canvas.speed = this.speedRange / 2 + Math.random() * (this.speedRange / 2);
+
+            ctx.save();
+            ctx.fillStyle = Confetti.CONST.COLORS[Math.random() * Confetti.CONST.COLORS.length | 0];
+            ctx.fillRect(0, 0, canvas.width, canvas.height);
+            ctx.restore();
+
+            this.sprites.push(canvas);
+          }
+        };
+
+        Confetti.prototype.render = function render(now) {
+          var progress = this.progress.tick(now);
+
+          this.canvas.width = this.width;
+          this.canvas.height = this.height;
+
+          for (var i = 0; i < this.length; ++i) {
+            this.ctx.save();
+            this.ctx.translate(this.sprites[i].position.initX + this.sprites[i].rotation * Confetti.CONST.ROTATION_RATE * progress, this.sprites[i].position.initY + progress * (this.height + this.yRange));
+            this.ctx.rotate(this.sprites[i].rotation);
+            this.ctx.drawImage(this.sprites[i], -Confetti.CONST.SPRITE_WIDTH * Math.abs(Math.sin(progress * Math.PI * 2 * this.sprites[i].speed)) / 2, -Confetti.CONST.SPRITE_HEIGHT / 2, Confetti.CONST.SPRITE_WIDTH * Math.abs(Math.sin(progress * Math.PI * 2 * this.sprites[i].speed)), Confetti.CONST.SPRITE_HEIGHT);
+            this.ctx.restore();
+          }
+
+          requestAnimationFrame(this.render);
+        };
+
+        _createClass(Confetti, null, [{
+          key: "CONST",
+          get: function get() {
+            return {
+              SPRITE_WIDTH: 9,
+              SPRITE_HEIGHT: 16,
+              PAPER_LENGTH: 100,
+              DURATION: 8000,
+              ROTATION_RATE: 50,
+              COLORS: ["#EF5350", "#EC407A", "#AB47BC", "#7E57C2", "#5C6BC0", "#42A5F5", "#29B6F6", "#26C6DA", "#26A69A", "#66BB6A", "#9CCC65", "#D4E157", "#FFEE58", "#FFCA28", "#FFA726", "#FF7043", "#8D6E63", "#BDBDBD", "#78909C"]
+            };
+          }
+        }]);
+
+        return Confetti;
+      }();
+
+      (function () {
+        var DURATION = 6000,
+          LENGTH = 220;
+
+        new Confetti({
+          width: window.innerWidth,
+          height: window.innerHeight,
+          length: LENGTH,
+          duration: DURATION
+        });
+
+        setTimeout(function () {
+          new Confetti({
+            width: window.innerWidth,
+            height: window.innerHeight,
+            length: LENGTH,
+            duration: DURATION
+          });
+        }, DURATION / 2);
+      })();
+    }
+  }
+}

+ 0 - 23
yarn.lock

@@ -1255,19 +1255,6 @@ amdefine@>=0.0.4:
   resolved "https://registry.npm.taobao.org/amdefine/download/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5"
   integrity sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=
 
-animated-number-vue@^1.0.0:
-  version "1.0.0"
-  resolved "http://nexus.wisdomcity.com.cn/repository/wisdomcity-npm-group/animated-number-vue/-/animated-number-vue-1.0.0.tgz#447ce78fc10c7f2c77df0ca454a1bc18052ebfc8"
-  integrity sha1-RHznj8EMfyx33wykVKG8GAUuv8g=
-  dependencies:
-    animejs "^2.2.0"
-    vue "^2.5.13"
-
-animejs@^2.2.0:
-  version "2.2.0"
-  resolved "http://nexus.wisdomcity.com.cn/repository/wisdomcity-npm-group/animejs/-/animejs-2.2.0.tgz#35eefdfc535b81949c9cb06f0b3e60c02e6fdc80"
-  integrity sha1-Ne79/FNbgZScnLBvCz5gwC5v3IA=
-
 ansi-colors@^3.0.0:
   version "3.2.4"
   resolved "https://registry.npm.taobao.org/ansi-colors/download/ansi-colors-3.2.4.tgz#e3a3da4bfbae6c86a9c285625de124a234026fbf"
@@ -8636,11 +8623,6 @@ vue-eslint-parser@^5.0.0:
     esquery "^1.0.1"
     lodash "^4.17.11"
 
-vue-flip-number@^1.1.1:
-  version "1.1.1"
-  resolved "http://nexus.wisdomcity.com.cn/repository/wisdomcity-npm-group/vue-flip-number/-/vue-flip-number-1.1.1.tgz#2cf1dd9fe7ac72d614206ec4b1f680a923af6aca"
-  integrity sha1-LPHdn+esctYUIG7EsfaAqSOvaso=
-
 vue-hot-reload-api@^2.3.0:
   version "2.3.4"
   resolved "https://registry.npm.taobao.org/vue-hot-reload-api/download/vue-hot-reload-api-2.3.4.tgz?cache=0&sync_timestamp=1568190386192&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fvue-hot-reload-api%2Fdownload%2Fvue-hot-reload-api-2.3.4.tgz#532955cc1eb208a3d990b3a9f9a70574657e08f2"
@@ -8690,11 +8672,6 @@ vue-template-es2015-compiler@^1.9.0:
   resolved "https://registry.npm.taobao.org/vue-template-es2015-compiler/download/vue-template-es2015-compiler-1.9.1.tgz#1ee3bc9a16ecbf5118be334bb15f9c46f82f5825"
   integrity sha1-HuO8mhbsv1EYvjNLsV+cRvgvWCU=
 
-vue@^2.5.13:
-  version "2.6.14"
-  resolved "http://nexus.wisdomcity.com.cn/repository/wisdomcity-npm-group/vue/-/vue-2.6.14.tgz#e51aa5250250d569a3fbad3a8a5a687d6036e235"
-  integrity sha1-5RqlJQJQ1Wmj+606ilpofWA24jU=
-
 vue@^2.6.10:
   version "2.6.10"
   resolved "https://registry.npm.taobao.org/vue/download/vue-2.6.10.tgz#a72b1a42a4d82a721ea438d1b6bf55e66195c637"