【vue自定义组件】24h倒计时组件

3,296 阅读3分钟

小知识,大挑战!本文正在参与“    程序员必备小知识    ”创作活动

本文同时参与 「掘力星计划」    ,赢取创作大礼包,挑战创作激励金

前言

佛祖保佑, 永无bug。Hello 大家好!我是海的对岸!

这个组件也算是一个通用的组件,在此记录一下。

实现

效果

countDown.gif

原理

原理很简单,大概撸一遍

  1. 获取当前时间(时分秒)
  2. 一天24小时 减去 获取的当前时间,得到倒计时时间
  3. 倒计时时间进行时分秒的判断,如果时分秒一位数,那么需要在前面补0
  4. 把处理好的倒计时时间显示出来
  5. 计时器接着进行步骤1 继续走

上代码:

<template>
  <div class="number-grow-warp">
    <span >{{time}}</span>
  </div>
  </template>
  <script>
  export default {
    data() {
      return {
        time: '24:00:00',
        timer: undefined, // 计时器,作用:组件销毁的时候需要把定时器清除
      }
    },
    mounted() {
      this.start();  // 24小时倒计时
    },
    methods: {
      //  获取当前时间的24小时倒计时
      countDown() {
        let now = new Date(); // 获取当前时间
        let hour = now.getHours(); // 时
        let min = now.getMinutes(); // 分
        let sec = now.getSeconds(); // 秒
        let result = ''; // 返回结果

        let h = 24 - hour; // 一天中剩下的时间(小时)
        if (min > 0 || sec > 0) {
            h -= 1
        }
        let m = 60 - min; // 一天中剩下的时间(分钟)
        if (sec > 0) {
            m -= 1
        }
        if (m == 60) {
            m = 0
        }
        let s = 60 - sec; // 一天中剩下的时间(秒)
        if (s == 60) {
            s = 0
        }

        h = h.toString();
        m = m.toString();
        s = s.toString();
        if (h.length == 1) { // 补0
            h = '0' + h
        }
        if (m.length == 1) { // 补0
            m = '0' + m
        }
        if (s.length == 1) // 补0
            s = '0' + s
        result = h + ':' + m + ':' + s
        return result
      },
      start() {
        this.timer = setInterval(function () {
          this.time = this.countDown();
        }, 1000)
      },
    },
    destroyed() {
      clearInterval(this.timer); // 组件销毁时清除定时器
    },
  }
  </script>
  <style scoped>

  </style>

计时器的方法没有问题,但是页面上并没有显示出倒计时,细心的大家有没有看出问题在哪里?

问题在setInterval这个函数上,这就引出了vue的thisfunction的this中间的出入了

vue的this 和 function的this

  1. vue中的this
  • 很好理解,这个this 指向的就是vue对象。比如,你在motheds中写了几个方法(xx1(), xx2(), ...),在mountedcreated,或watch钩子中使用,都可以直接this.xx1(),直接调用方法
  1. functionthis:
  • 这个this指向window
  • 普通函数中的this指向是变化的谁调用指向谁,因为 setIntervalsetTimeout 是挂载在 window 上的,相当于window.setIntervalwindow.setTimeout,所以执行函数中的 this 指向 window
  • 箭头函数呢?箭头函数中的this指向是固定不变(定义函数时的指向)

解决this的问题

同样是上面的代码,改动的地方就在start()

  1. 方法1
  • 箭头函数(简单粗暴)
start() {
    setInterval(() => {
        this.time = this.countDown();
    }, 1000)
}

试验下直接在start()不使用箭头函数呢?答案是undefined

start() {
    setInterval(function() {
        console.log(this.time); // 打印出undefined
    }, 1000)
}
  1. 方法2
  • setIntervalsetTimeout第三个参数
  • 原理:setIntervalsetTimeout第三个参数可以作为执行函数的参数,具体用法看下文代码
start() {
    setInterval(
        _this => {
            console.log(_this.time); // 打印出具体时间
            _this.time = this.countDown();
        },
        500,
        this
    );
}
  1. 保存一下 this
start() {
     let that = this;
     setInterval(() => {
       console.log(that.time); // 打印出具体时间
       that.time = this.countDown();
    }, 500);
}

最后完整代码

com24hourCountDown.vue

<template>
  <div class="number-grow-warp">
    <span ref="time">{{time}}</span>
  </div>
  </template>
  <script>

  export default {
    data() {
      return {
        time: '24:00:00',
        timer: undefined, // 计时器,作用:组件销毁的时候需要把定时器清除
      }
    },
    mounted() {
      this.start();  // 24小时倒计时
    },
    methods: {
      //  获取当前时间的24小时倒计时
      countDown() {
        let now = new Date(); // 获取当前时间
        let hour = now.getHours(); // 时
        let min = now.getMinutes(); // 分
        let sec = now.getSeconds(); // 秒
        let result = ''; // 返回结果

        let h = 24 - hour; // 一天中剩下的时间(小时)
        if (min > 0 || sec > 0) {
            h -= 1
        }
        let m = 60 - min; // 一天中剩下的时间(分钟)
        if (sec > 0) {
            m -= 1
        }
        if (m == 60) {
            m = 0
        }
        let s = 60 - sec; // 一天中剩下的时间(秒)
        if (s == 60) {
            s = 0
        }

        h = h.toString();
        m = m.toString();
        s = s.toString();
        if (h.length == 1) { // 补0
            h = '0' + h
        }
        if (m.length == 1) { // 补0
            m = '0' + m
        }
        if (s.length == 1) // 补0
            s = '0' + s
        result = h + ':' + m + ':' + s
        return result
      },
      start() {
        setInterval(() => {
          this.time = this.countDown();
        }, 1000)

        // 测试1
        // setInterval(function() {
        //   console.log(this.time); // undefined
        // }, 500);
        // 测试2
        // setInterval(() => {
        //   console.log(this.time); // 具体时间
        // }, 500);
        // 测试3
        // setInterval(
        //   _this => {
        //     console.log(_this.time); // 具体时间
        //     _this.time = this.countDown();
        //   },
        //   500,
        //   this
        // );
        // 测试4
        // let that = this;
        // setInterval(() => {
        //   console.log(that.time);// 具体时间
        //   that.time = this.countDown();
        // }, 500);
      },

    },
    destroyed() {
      clearInterval(this.timer); // 组件销毁时清除定时器
    },
  }
  </script>
  <style scoped>
  </style>

然后我们引用一下

<template>
  <div>
    <module />
  </div>
</template>

<script>
// 旋转展示数值组件
import module from './../../components/com24hourCountDown'
export default {
  name: 'test',
  components: {
    module,
  },
  data() {
    return {
    }
  },
  methods: {
  },
  mounted() {
  },
}
</script>

<style scope>
</style>

参考文章

  1. Vue中setInterval和setTimeout执行函数中的this的指向

评论抽奖

欢迎在评论区讨论,掘金官方将在掘力星计划活动结束后,在评论区抽送100份掘金周边

  • 抽奖礼物:100份,掘金官方提供,包括掘金徽章、拖鞋、马克杯、帆布袋等,随机发放
  • 抽奖时间:「掘力星计划」活动结束后,预计3个工作日内,官方将在所有符合规则的活动文章评论区抽出
  • 抽奖方式:掘金官方随机抽奖+人工核实
  • 评论内容:与文章内容相关的评论、建议、讨论等,「踩踩」「学习了」等泛泛类的评论无法获奖

都看到这里了,求各位观众大佬们点个赞再走吧,你的赞对我非常重要