tn-verification-code.vue 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. <template>
  2. <view class="tn-code-class tn-code">
  3. </view>
  4. </template>
  5. <script>
  6. export default {
  7. name: 'tn-verification-code',
  8. props: {
  9. // 倒计时总秒数
  10. seconds: {
  11. type: Number,
  12. default: 60
  13. },
  14. // 开始时提示文字
  15. startText: {
  16. type: String,
  17. default: '获取验证码'
  18. },
  19. // 倒计时提示文字
  20. countDownText: {
  21. type: String,
  22. default: 's秒后重新获取'
  23. },
  24. // 结束时提示文字
  25. endText: {
  26. type: String,
  27. default: '重新获取'
  28. },
  29. // 是否在H5刷新或各端返回再进入时继续倒计时
  30. keepRunning: {
  31. type: Boolean,
  32. default: false
  33. },
  34. // 为了区分多个页面,或者一个页面多个倒计时组件本地存储的继续倒计时变了
  35. uniqueKey: {
  36. type: String,
  37. default: ''
  38. }
  39. },
  40. data() {
  41. return {
  42. timer: null,
  43. secNum: this.seconds,
  44. // 是否可以执行验证码操作
  45. canGetCode: true
  46. }
  47. },
  48. watch: {
  49. seconds: {
  50. handler(n) {
  51. this.secNum = n
  52. },
  53. immediate: true
  54. }
  55. },
  56. mounted() {
  57. this.checkKeepRunning()
  58. },
  59. beforeDestroy() {
  60. this.setTimeToStorage()
  61. if (this.timer) {
  62. clearInterval(this.timer)
  63. this.timer = null
  64. }
  65. },
  66. methods: {
  67. // 检查是否继续运行
  68. checkKeepRunning() {
  69. // 获取上一次退出页面时的时间戳,如果没有上次保存,该值为空
  70. let lastTimestamp = Number(uni.getStorageSync(this.uniqueKey + '_$tCountDownTimestamp'))
  71. if (!lastTimestamp) return this.changeEvent(this.startText)
  72. // 当前秒的时间戳
  73. // + new Date() 相当于 new Date().getTime()
  74. let nowTimestamp = Math.floor((+ new Date()) / 1000)
  75. // 判断当前的时间戳,是否小于上一次的设定结束的时间,提前于结束的时间戳
  76. if (this.keepRunning && lastTimestamp && lastTimestamp > nowTimestamp) {
  77. // 剩余尚未执行完倒计时秒数
  78. this.secNum = lastTimestamp - nowTimestamp
  79. // 清除本地保存的变量
  80. uni.removeStorageSync(this.uniqueKey + '_$tCountDownTimestamp')
  81. // 开始倒计时
  82. this.start()
  83. } else {
  84. // 如果不存在需要继续上一次的倒计时,执行正常的逻辑
  85. this.changeEvent(this.startText);
  86. }
  87. },
  88. // 开始倒计时
  89. start() {
  90. // 防止快速点击获取验证码按钮导致产生多个定时器导致混乱
  91. if (this.timer) {
  92. clearInterval(this.timer)
  93. this.timer = null
  94. }
  95. this.$emit('start')
  96. this.canGetCode = false
  97. this.changeEvent(this.countDownText.replace(/s|S/, this.secNum))
  98. this.setTimeToStorage()
  99. this.timer = setInterval(() => {
  100. if (--this.secNum) {
  101. this.changeEvent(this.countDownText.replace(/s|S/, this.secNum))
  102. } else {
  103. // 倒计时结束,清空定时器、重置提示信息
  104. this.reset()
  105. this.$emit('end')
  106. }
  107. }, 1000)
  108. },
  109. // 重置倒计时
  110. reset() {
  111. this.canGetCode = true
  112. if (this.timer) {
  113. clearInterval(this.timer)
  114. this.timer = null
  115. }
  116. this.secNum = this.seconds
  117. this.changeEvent(this.endText)
  118. },
  119. // 倒计时改变事件
  120. changeEvent(text) {
  121. this.$emit('change', text)
  122. },
  123. // 保存当前时间戳
  124. // 防止倒计时尚未结束,H5刷新或者各端的右上角返回上一页再进来
  125. setTimeToStorage() {
  126. if (!this.keepRunning ||!this.timer) return
  127. // 记录当前的时间戳,为了下次进入页面,如果还在倒计时内的话,继续倒计时
  128. // 倒计时尚未结束,结果大于0;倒计时已经开始,就会小于初始值,如果等于初始值,说明没有开始倒计时,无需处理
  129. if (this.secNum > 0 && this.secNum <= this.seconds) {
  130. let nowTimestamp = Math.floor((+ new Date()) / 1000)
  131. // 保存本次倒计时结束时候的时间戳
  132. uni.setStorageSync(this.uniqueKey + '_$tCountDownTimestamp', nowTimestamp + this.secNum)
  133. }
  134. }
  135. }
  136. }
  137. </script>
  138. <style lang="scss" scoped>
  139. .tn-code {
  140. width: 0;
  141. height: 0;
  142. position: fixed;
  143. z-index: -1;
  144. }
  145. </style>