【study】Vue中封装一个日期函数

1,928 阅读5分钟

1.主要使用原生的原理在vue中实现(自己拼接字符串)

<template>
  <div>
    <div>{{ times }}</div>
  </div>
</template>
<script>
export default {
  data() {
    return {
      times: "",
    };
  },
  mounted() {
      setInterval(() => {
        var datetime = new Date();
        var year = datetime.getFullYear();
        //此时的三元判断,实际上可以利用字符串的方法padStart去补全,使用方法String.prototype.padStart.call(xx,2,"0"),第一个参数补齐的元素,第二个参数表示补足两位,第三个参数表示用0去补齐
        var month =datetime.getMonth() + 1 < 10 ? "0" + (datetime.getMonth() + 1): datetime.getMonth() + 1;
        var date =  datetime.getDate() < 10 ? "0" + datetime.getDate() : datetime.getDate();
        var hour = datetime.getHours() < 10 ? "0" + datetime.getHours():datetime.getHours();
        var minutes = datetime.getMinutes() < 10 ? "0" + datetime.getMinutes():datetime.getMinutes();
        var seconds = datetime.getSeconds() < 10 ? "0" + datetime.getSeconds():datetime.getSeconds();
        //times是定义的字符串,最后拼接出此时此刻的时间
        this.times =  year+" / " + month+" /" + date+" / "+ hour+" : " + minutes+" : " + seconds ;
        console.log( this.times)
      }, 1000);
   },
};
</script>

  • 这种写法,每秒都在更新这个字符串,但是实际上,每秒不是时分秒都在变化,所以实际上这种写法的性能不是很好,按需求,我们应该局部更新视图,所以我们可以按需,把时分秒做成一个组件,然后就变成按需渲染了

2.利用本地的时间表示方式(根据语言选择合适的显示方式)

<template>
  <div>
    <div>{{ times }}</div>
  </div>
</template>
<script>
export default {
  data() {
    return {
      times: "",
    };
  },
  mounted() {
       setInterval(() => {
       //本地化接口
       this.times = new Date().toLocaleString();
      }, 1000);
      //去掉多余的计算过程,结果适应性会更好
  },
};
</script>

3.封装一个带有星期的时间

function getDate () {
      const now = new Date()
      const y = now.getFullYear()
      const month = now.getMonth() + 1 < 10 ? '0' + (now.getMonth() + 1) : now.getMonth() + 1
      const d = now.getDate() < 10 ? '0' + now.getDate() : now.getDate()
      const h = now.getHours() < 10 ? '0' + now.getHours() : now.getHours()
      const m = now.getMinutes() < 10 ? '0' + now.getMinutes() : now.getMinutes()
      const s = now.getSeconds() < 10 ? '0' + now.getSeconds() : now.getSeconds()
      const w = '星期' + '日一二三四五六'.charAt(now.getDay())
      this.timeNow = h + ':' + m + ':' + s
      this.weekNow = w
      this.dataNow = y + '/' + month + '/' + d
      return this.timeNow && this.weekNow && this.dataNow
    }

4.moment插件

momentjs.com/

 // mixins.js
// 封装一个日期函数 
import moment from 'moment'
export const nowDate = {
  data() {
    return {
      timeNow: '', // 例如: 10:22:34
      weekNow: '', // 例如:星期一
      dataNow: '', // 例如:2021/11/05
      startDayTime: '', // 例如:2021-10-05
      endDayTime: '', // 例如:startTime + 1,2021-10-06
      startWeekTime: '', // 例如:2021-11-08,每周的周一
      endWeekTime: '', // 例如:2021-11-14,每周的周日
      startMonthTime: '', // 例如:2021-11-01,每月第一天
      endMonthTime: '', // 例如:2021-11-30,每月最后一天
      startYearTime: '', // 例如:2021-01-01,每年第一天
      endYearTime: '', // 例如:2021-12-31,每年最后一天
    }
  },
  methods: {
    getDate() {
      this.timeNow = moment().format('HH:mm:ss')
      this.weekNow = moment().isoWeekday()
      this.dataNow = moment().format('YYYY/MM/DD')
      this.startDayTime = moment().format('YYYY-MM-DD')
      this.endDayTime = moment().add(1,'day').format('YYYY-MM-DD')
      this.startWeekTime = moment().startOf('week').add(1,'day').format('YYYY-MM-DD')
      this.endWeekTime = moment().endOf('week').add(1,'day').format('YYYY-MM-DD')
      this.startMonthTime = moment().startOf('month').format('YYYY-MM-DD')
      this.endMonthTime = moment().endOf('month').format('YYYY-MM-DD')
      this.startYearTime = moment().startOf('year').format('YYYY-MM-DD')
      this.endYearTime = moment().endOf('year').format('YYYY-MM-DD')
    }
  },
  created() {
    this.getDate()
  }
}
  • 如果想要正常显示“星期一”这种格式,需要简单处理一下
星期{{ week|getweek }}

// 过滤
 filters: {
    getweek(e) {
      var week = ['一', '二', '三', '四', '五', '六', '日']
      return week[e - 1]
    },
  },

5.注:什么是宏任务和微任务???

juejin.im/post/688078…

1.这里第一种和第二种实现方式,涉及的setInterval定时器,定时器任务是宏任务,因为是在不同的进程中进行的
2.就会有个问题,如果JS被阻塞了,JS后续的代码是不会被执行的,但是计时器会继续走
3.这样的话,每过1秒,定时器就会发出一个信号,要执行一下这个任务,这时候,因为JS的阻塞,其实信号接收也被阻塞了,或者说,即是收到了一堆任务,也无法立即执行
4.当时机切换到有剩余资源可以执行时,此时因为堆积了很多未执行的任务,所以会一下子把堆积的任务都执行掉,这就会造成一个可怕的结果,一瞬间造成大量的重绘
5.这里的重绘只有在原生和用setInterval的时候才会出现,为什么呢?
  1. 因为Vue的渲染设计的是微任务,大量堆积的任务执行时同步的,前面的定时器通知要执行这个动作是异步的,所以对于Vue来说,是不会造成大量的重绘的
  2. 但是this.times仍然会一下子被设置很多次,设置多次也就意味着经历了多次的Vue的劫持,Vue内部的逻辑也会一下子经历多次
  3. 这只是因为我在页面上显示的是实时时间,才不会造成问题
6.如果换成倒计时显示,很多人会设置每秒减1,这就会变成,当阻塞时,倒计时不动,阻塞时,倒计时不动是正常的,因为资源被占满了,不重绘也正常,但是,如果当有资源的话,一下子就会执行多次,就会看到屏幕上疯狂的倒计时递减,但其实,只要当有足够资源时,更新一次就行了,所以一种方法是可以用setTimeout替换setInterval
7.使用setTimeout+递归,替换setInterval,setTimeout仍然会有和setInterval一样的问题,但是会有个区别,因为setTimeout实现不断更新的逻辑是不停的循环调用自己,所以即使主线程阻塞,定时器只会通知一次,要执行回调,实际上,应该总是用setTimeout,尽量少用setInterval,原因是我们太容易遇到阻塞了
  1. 常见的阻塞场景:浏览器TAB页的切换,浏览器会挂起这个标签页的执行栈,也就是不在执行JS了,这个就相当于阻塞了
  2. 事件管理是不管标签页的,它有浏览器的时间管理统一管理,setInterval是让定时器每隔一段时间告诉主线程要执行任务了,然后调用自身说的是要用setTimeout实现setInterval的效果,肯定要写出递归的方法,调用自身
8.最后看宏任务的问题,哪怕已经改成了setTimeout,仍然会存在问题,问题在于两点:
  1. 宏任务因为存在资源的切换,所以设置的1秒后,肯定是大于等于1秒
  2. 开始的执行的实际不确定,因为你并不能保证程序执行的开始时间正好是整秒开始
9.因为上述两个问题,可能对于秒来说,感觉不出什么,但是对于分呢?因为在前端上来说,喵不是最小的单位,还可以获取到比秒更精确的数值,那么总应该使用更精确的方式去获取数据,前端能获取到的最小单位是高精度的微秒
10.所以如果实现一个秒表计时,用setTimeout和setInterval根本做不了,只能做到秒,但是秒后面的小数点该怎么做呢,要间隔多久更新一次呢?
11.我们无法知道要隔着多少秒去获取一下时间,因为时间时不断变化的,但是我们知道渲染的间隔,只要在每次渲染时去获取实时的精确的时间,所以,最好的方法,我们不应该使用宏任务,而应该使用微任务去做