0

I'm trying to animate a counter that I've made with Vue.js.

The value is being animated by Tween.js and then formatted with Numeral js but I'm having an issue.

I'd like to increment by a random amount, and when I increment, animate the number from whatever it is currently showing to the new total.

I have num which holds the final value of the counter, and displayNum which holds the animating value.

The issue is that my current code (if you hammer the increment button) sometimes starts animating the number from 0, rather than the current total. Especially when you get to over 1,000.

How can I stop this behaviour?

At present, whenever you click increment it takes the currently displayed number and starts a new tween to the target number.

function animate(time) {
    requestAnimationFrame(animate);
    TWEEN.update(time);
}
requestAnimationFrame(animate);

var v = new Vue({
  'el' : '#app',
  'data' : {
    num : 0,
    displayNum : 0,
    tween : false
  },
  methods:{
    increment(){
      var vm = this;
      // select a random number and add it to our target
      vm.num += Math.round(Math.random() * 300);
      // create an object that we can use tween.js to animate
      var anim = { num: vm.displayNum };
      // if we are already animating, stop the animation
      if( vm.tween ){
        vm.tween.stop();
      }
      // create a new animation from the current number
      vm.tween = new TWEEN.Tween(anim)
        // to our new target
        .to({ num : vm.num }, 3000)
        .easing(TWEEN.Easing.Quadratic.Out)
        .onUpdate(function() {
        
          // Failed attempt to debug
          if( anim.num < vm.displayNum ){
            console.log("Something isn't right");
          }
          // on update, replace the display number with a rounded, formatted 
          // version of the animating number
          vm.displayNum = numeral(Math.round(anim.num)).format('0,0');
        })
        // if the tween ever stops, set the vm's current tween to 
        // false
        .onStop(function(){
          vm.tween = false;
        })
        .start();
    }
  }
})
html, body{
  height:100%;
}
body{
  display:flex;
  align-items:center;
  justify-content:center;
}
.window{
  width:200px;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.6.1/css/bulma.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/numeral.js/2.0.6/numeral.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tween.js/r14/Tween.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.3/vue.min.js"></script>


<div id="app">
  <div class="window has-text-centered">
    <div class="is-size-1">
      <span v-html="displayNum"></span>
    </div>
    <div>
      <button class="button" @click="increment">Increment</button>
    </div>
    <div class="is-size-7">
      <span v-html="num"></span>
    </div>
  </div>
</div>

4

1 回答 1

1

问题是您将字符串和整数混合在一起。首先,确保 displayNum 是模型上的字符串,然后在初始化动画时确保 parseInt 它同时删除超过 999 时显示的逗号。

function animate(time) {
    requestAnimationFrame(animate);
    TWEEN.update(time);
}
requestAnimationFrame(animate);

var v = new Vue({
  'el' : '#app',
  'data' : {
    num : 0,
    displayNum : "0",
    tween : false
  },
  methods:{
    increment(){
      var vm = this;
      // select a random number and add it to our target
      vm.num += Math.round(Math.random() * 300);
      // create an object that we can use tween.js to animate
      var anim = { num: parseInt(vm.displayNum.replace(",","")) };
      // if we are already animating, stop the animation
      if( vm.tween ){
        vm.tween.stop();
      }
      // create a new animation from the current number
      vm.tween = new TWEEN.Tween(anim)
        // to our new target
        .to({ num : vm.num }, 3000)
        .easing(TWEEN.Easing.Quadratic.Out)
        .onUpdate(function() {
        
          // Failed attempt to debug
          //if( anim.num < vm.displayNum ){
          //  console.log("Something isn't right", anim, vm.displayNum);
          //}
          // on update, replace the display number with a rounded, formatted 
          // version of the animating number
          vm.displayNum = numeral(Math.round(anim.num)).format('0,0');
        })
        // if the tween ever stops, set the vm's current tween to 
        // false
        .onStop(function(){
          vm.tween = false;
        })
        .start();
    }
  }
})
html, body{
  height:100%;
}
body{
  display:flex;
  align-items:center;
  justify-content:center;
}
.window{
  width:200px;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.6.1/css/bulma.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/numeral.js/2.0.6/numeral.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tween.js/r14/Tween.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.3/vue.min.js"></script>


<div id="app">
  <div class="window has-text-centered">
    <div class="is-size-1">
      <span v-html="displayNum"></span>
    </div>
    <div>
      <button class="button" @click="increment">Increment</button>
    </div>
    <div class="is-size-7">
      <span v-html="num"></span>
    </div>
  </div>
</div>

于 2017-12-08T20:08:25.190 回答