bug
jiangping
2023-11-07 64b432916af9c9218ab3f3eca614e26c542142ae
minipro_standard/uni_modules/uview-ui/components/u-code/u-code.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,129 @@
<template>
   <view class="u-code">
      <!-- æ­¤ç»„件功能由js完成,无需写html逻辑 -->
   </view>
</template>
<script>
   import props from './props.js';
   /**
    * Code éªŒè¯ç è¾“入框
    * @description è€ƒè™‘到用户实际发送验证码的场景,可能是一个按钮,也可能是一段文字,提示语各有不同,所以本组件 ä¸æä¾›ç•Œé¢æ˜¾ç¤ºï¼Œåªæä¾›æç¤ºè¯­ï¼Œç”±ç”¨æˆ·å°†æç¤ºè¯­åµŒå…¥åˆ°å…·ä½“的场景
    * @tutorial https://www.uviewui.com/components/code.html
    * @property {String | Number}   seconds         å€’计时所需的秒数(默认 60 ï¼‰
    * @property {String}         startText      å¼€å§‹å‰çš„æç¤ºè¯­ï¼Œè§å®˜ç½‘说明(默认 '获取验证码' ï¼‰
    * @property {String}         changeText      å€’计时期间的提示语,必须带有字母"x",见官网说明(默认 'X秒重新获取' ï¼‰
    * @property {String}         endText         å€’计结束的提示语,见官网说明(默认 '重新获取' ï¼‰
    * @property {Boolean}         keepRunning      æ˜¯å¦åœ¨H5刷新或各端返回再进入时继续倒计时( é»˜è®¤false ï¼‰
    * @property {String}         uniqueKey      ä¸ºäº†åŒºåˆ†å¤šä¸ªé¡µé¢ï¼Œæˆ–者一个页面多个倒计时组件本地存储的继续倒计时变了
    *
    * @event {Function}   change   å€’计时期间,每秒触发一次
    * @event {Function}   start   å¼€å§‹å€’计时触发
    * @event {Function}   end      ç»“束倒计时触发
    * @example <u-code ref="uCode" @change="codeChange" seconds="20"></u-code>
    */
   export default {
      name: "u-code",
      mixins: [uni.$u.mpMixin, uni.$u.mixin,props],
      data() {
         return {
            secNum: this.seconds,
            timer: null,
            canGetCode: true, // æ˜¯å¦å¯ä»¥æ‰§è¡ŒéªŒè¯ç æ“ä½œ
         }
      },
      mounted() {
         this.checkKeepRunning()
      },
      watch: {
         seconds: {
            immediate: true,
            handler(n) {
               this.secNum = n
            }
         }
      },
      methods: {
         checkKeepRunning() {
            // èŽ·å–ä¸Šä¸€æ¬¡é€€å‡ºé¡µé¢(H5还包括刷新)时的时间戳,如果没有上次的保存,此值可能为空
            let lastTimestamp = Number(uni.getStorageSync(this.uniqueKey + '_$uCountDownTimestamp'))
            if(!lastTimestamp) return this.changeEvent(this.startText)
            // å½“前秒的时间戳
            let nowTimestamp = Math.floor((+ new Date()) / 1000)
            // åˆ¤æ–­å½“前的时间戳,是否小于上一次的本该按设定结束,却提前结束的时间戳
            if(this.keepRunning && lastTimestamp && lastTimestamp > nowTimestamp) {
               // å‰©ä½™å°šæœªæ‰§è¡Œå®Œçš„倒计秒数
               this.secNum = lastTimestamp - nowTimestamp
               // æ¸…除本地保存的变量
               uni.removeStorageSync(this.uniqueKey + '_$uCountDownTimestamp')
               // å¼€å§‹å€’计时
               this.start()
            } else {
               // å¦‚果不存在需要继续上一次的倒计时,执行正常的逻辑
               this.changeEvent(this.startText)
            }
         },
         // å¼€å§‹å€’计时
         start() {
            // é˜²æ­¢å¿«é€Ÿç‚¹å‡»èŽ·å–éªŒè¯ç çš„æŒ‰é’®è€Œå¯¼è‡´å†…éƒ¨äº§ç”Ÿå¤šä¸ªå®šæ—¶å™¨å¯¼è‡´æ··ä¹±
            if(this.timer) {
               clearInterval(this.timer)
               this.timer = null
            }
            this.$emit('start')
            this.canGetCode = false
            // è¿™é‡Œæ”¾è¿™å¥ï¼Œæ˜¯ä¸ºäº†ä¸€å¼€å§‹æ—¶å°±æç¤ºï¼Œå¦åˆ™è¦ç­‰setInterval的1秒后才会有提示
            this.changeEvent(this.changeText.replace(/x|X/, this.secNum))
            this.timer = setInterval(() => {
               if (--this.secNum) {
                  // ç”¨å½“前倒计时的秒数替换提示字符串中的"x"字母
                  this.changeEvent(this.changeText.replace(/x|X/, this.secNum))
               } else {
                  clearInterval(this.timer)
                  this.timer = null
                  this.changeEvent(this.endText)
                  this.secNum = this.seconds
                  this.$emit('end')
                  this.canGetCode = true
               }
            }, 1000)
        this.setTimeToStorage()
      },
         // é‡ç½®ï¼Œå¯ä»¥è®©ç”¨æˆ·å†æ¬¡èŽ·å–éªŒè¯ç 
         reset() {
            this.canGetCode = true
            clearInterval(this.timer)
            this.secNum = this.seconds
            this.changeEvent(this.endText)
         },
         changeEvent(text) {
            this.$emit('change', text)
         },
         // ä¿å­˜æ—¶é—´æˆ³ï¼Œä¸ºäº†é˜²æ­¢å€’计时尚未结束,H5刷新或者各端的右上角返回上一页再进来
         setTimeToStorage() {
            if(!this.keepRunning || !this.timer) return
            // è®°å½•当前的时间戳,为了下次进入页面,如果还在倒计时内的话,继续倒计时
            // å€’计时尚未结束,结果大于0;倒计时已经开始,就会小于初始值,如果等于初始值,说明没有开始倒计时,无需处理
            if(this.secNum > 0 && this.secNum <= this.seconds) {
               // èŽ·å–å½“å‰æ—¶é—´æˆ³(+ new Date()为特殊写法),除以1000变成秒,再去除小数部分
               let nowTimestamp = Math.floor((+ new Date()) / 1000)
               // å°†æœ¬è¯¥ç»“束时候的时间戳保存起来 => å½“前时间戳 + å‰©ä½™çš„ç§’æ•°
               uni.setStorage({
                  key: this.uniqueKey + '_$uCountDownTimestamp',
                  data: nowTimestamp + Number(this.secNum)
               })
            }
         }
      },
      // ç»„件销毁的时候,清除定时器,否则定时器会继续存在,系统不会自动清除
      beforeDestroy() {
         this.setTimeToStorage()
         clearTimeout(this.timer)
         this.timer = null
      }
   }
</script>
<style lang="scss" scoped>
   @import "../../libs/css/components.scss";
</style>