如何在 Vue.js 中创建一个简单的 10 秒倒计时?

38

我想要做一个简单的从10倒数到0的计时器。

我在网上找到了使用普通JavaScript的解决方案,但是假设我想在Vue中实现它。这是使用jQuery的解决方案。

创建一个简单的10秒倒计时

<template>
   {{ countDown }}

</template>

<script>
  export default {
    computed: {
       countDown() {
         // How do i do the simple countdown here?
       }

    }

  }

</script>

我该如何在Vue.js中复现相同的功能?

谢谢

7个回答

73

虽然接受的答案可以工作并且很好,但实际上可以通过利用Vue.js watchers 以稍微简单的方式实现:

<template>
    {{ timerCount }}
</template>

<script>

    export default {

        data() {
            return {
                timerCount: 30
            }
        },

        watch: {

            timerCount: {
                handler(value) {

                    if (value > 0) {
                        setTimeout(() => {
                            this.timerCount--;
                        }, 1000);
                    }

                },
                immediate: true // This ensures the watcher is triggered upon creation
            }

        }
    }

</script>
使用此方法的好处是可以通过简单地设置 timerCount 的值来立即重置计时器。

如果您想要播放/暂停计时器,则可以按以下方式实现(请注意 - 这不是完美的解决方案,因为它将四舍五入到最近的一秒):

<template>
    {{ timerCount }}
</template>

<script>

    export default {

        data() {
            return {
                timerEnabled: true,
                timerCount: 30
            }
        },

        watch: {

            timerEnabled(value) {
                if (value) {
                    setTimeout(() => {
                        this.timerCount--;
                    }, 1000);
                }
            },

            timerCount: {
                handler(value) {

                    if (value > 0 && this.timerEnabled) {
                        setTimeout(() => {
                            this.timerCount--;
                        }, 1000);
                    }

                },
                immediate: true // This ensures the watcher is triggered upon creation
            }

        }

        methods: {

            play() {
                this.timerEnabled = true;
            },

            pause() {
                this.timerEnabled = false;
            }

        }

    }

</script>

1
倒计时在开始时不是线性的。 - Rejaul
1
如果你想允许重新启动计时器,你需要保存timeoutId,并在重新启动时调用clearTimeout。 - David 天宇 Wong

67

请确认这对您是否有效。

<template>
   {{ countDown }}
</template>

<script>
    export default {
        data () {
            return {
                countDown: 10
            }
        },
        methods: {
            countDownTimer () {
                if (this.countDown > 0) {
                    setTimeout(() => {
                        this.countDown -= 1
                        this.countDownTimer()
                    }, 1000)
                }
            }
        },
        created () {
            this.countDownTimer()
        }
    }
</script>

10
这是我为倒计时器制作的组件:
<template>
  <div>
    <slot :hour="hour" :min="min" :sec="sec"></slot>
  </div>
</template>

<script>
export default {
  props : {
    endDate : {  // pass date object till when you want to run the timer
      type : Date,
      default(){
        return new Date()
      }
    },
    negative : {  // optional, should countdown after 0 to negative
      type : Boolean,
      default : false
    }
  },
  data(){
    return{
      now : new Date(),
      timer : null
    }
  },
  computed:{
    hour(){
      let h = Math.trunc((this.endDate - this.now) / 1000 / 3600);
      return h>9?h:'0'+h;
    },
    min(){
      let m = Math.trunc((this.endDate - this.now) / 1000 / 60) % 60;
      return m>9?m:'0'+m;
    },
    sec(){
      let s = Math.trunc((this.endDate - this.now)/1000) % 60
      return s>9?s:'0'+s;
    }
  },
  watch : {
    endDate : {
      immediate : true,
      handler(newVal){
        if(this.timer){
          clearInterval(this.timer)
        }
        this.timer = setInterval(()=>{
          this.now = new Date()
          if(this.negative)
            return
          if(this.now > newVal){
            this.now = newVal
            this.$emit('endTime')
            clearInterval(this.timer)
          }
        }, 1000)
      }
    }
  },
  beforeDestroy(){
    clearInterval(this.timer)
  }
}
</script>

嗨@user8805101,当我尝试你的代码时,出现了错误:无效的属性:属性“endDate”的类型检查失败。期望日期,但得到的是值为“2021-11-03 15:23”的字符串。如何从父组件发送日期? - user6085744

1

如果有人使用Luxon的DateTime对象而不是本地JS的Date对象。

<template>
  <span v-if="timer">
    {{ timeCalculated }}
  </span>
</template>

<script>
import { DateTime } from 'luxon'

export default {
  name: 'CountDownTimer',

  props: {
    endDate: {
      type: String,
      required: true
    }
  },

  data () {
    return {
      now: DateTime.local(),
      timer: null
    }
  },

  computed: {
    timeCalculated () {
      const endDateDateTimeObj = DateTime.fromISO(this.endDate)
      const theDiff = endDateDateTimeObj.diff(this.now, ['hours', 'minutes', 'seconds'])

      return `${theDiff.hours}:${theDiff.minutes}:${Math.round(theDiff.seconds)}`
    }
  },

  watch: {
    endDate: {
      immediate: true,

      handler (endDateTimeStr) {
        const endDateTimeObj = DateTime.fromISO(endDateTimeStr)

        if (this.timer) {
          clearInterval(this.timer)
        }

        this.timer = setInterval(() => {
          this.now = DateTime.local()

          if (this.now > endDateTimeObj) {
            this.now = endDateTimeObj
            clearInterval(this.timer)
          }
        }, 1000)
      }
    }
  },

  beforeDestroy () {
    clearInterval(this.timer)
  }
}
</script>

在我的情况下,endDate 的类型为字符串,因为该值是从 JSON 中恢复的。您可以轻松地将其更改为原始的 DateTime 对象。

1
将其制作为组件,以便您可以重复使用它。
<body>
    <div id="app">
        <counter></counter>
        <counter></counter>
        <counter></counter>
    </div>
    <script>
        Vue.component('counter', {
            template: '<button v-on:click="countDownTimer()">{{ countDown }}</button>',
            data: function () {
                return {
                    countDown: 10,
                    countDownTimer() {
                        if (this.countDown > 0) {
                            setTimeout(() => {
                                this.countDown -= 1
                                this.countDownTimer();
                            }, 1000)
                        }
                    }
                }
            }
        })

        const app = new Vue({
            el: '#app'
        })
    </script>
</body>

0
使用日期。
<template>
  <div>{{ time }}</div>
</template>

<script>
export default {
  name: 'Timer',

  props: ['seconds'],

  data: () => ({
    interval: undefined,
    end: new Date(0, 0, 0),
    current: new Date(0, 0, 0, 0, 0, this.seconds)
  }),

  computed: {
    time: {
      get() {
        return this.current.getSeconds();
      },

      set(d) {
        this.current = new Date(0, 0, 0, 0, 0, this.current.getSeconds() + d);
      }
    }
  },

  methods: {
    countDown() {
      this.end >= this.current
        ? clearInterval(this.interval)
        : (this.time = -1);
    }
  },

  created() {
    this.interval = setInterval(this.countDown, 1000);
  }
};
</script>

0

这样做的最干净的方式是使用"setInterval"它本身就是递归的,可以防止不必要的样板文件。将其放入变量 ''interval'' 中,以便内部可以使用 "clearInterval" 停止递归。

回答问题:

data () {
   return {
      countDown: 10
   }
},


interval = setInterval(() => { 
    if(this.countDown == 0) clearInterval(interval)
    this.countDown--; 
}, 1000)

对于那些在这里寻找普通计时器的人:

// mounted
interval = setInterval(() => { this.seconds += 1;  }

//html or computed
Math.floor(this.seconds/ 60) % 60 // seconds
Math.floor(this.recordTimer / (60 * 60)) % 60 // hours

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接