微信小程序 == 倒计时验证码组件 (countdown-verify)

组件介绍

这是一个用于获取验证码的倒计时按钮组件,支持自定义倒计时时间、按钮样式和文字格式。

基本用法

javascript 复制代码
<countdown-verify 
  seconds="60"
  button-text="获取验证码"
  bind:send="onSendVerifyCode"
/>

属性说明

属性名 类型 默认值 说明
seconds Number 60 倒计时总时长(秒),必须大于0
buttonText String "获取验证码" 按钮默认显示的文字
countdownFormat String "剩余%s秒" 倒计时过程中显示的文字格式,%s会被替换为剩余秒数
buttonStyle String "" 按钮的样式,支持内联样式
disabledStyle String "background-color: #cccccc; color: #ffffff;" 倒计时过程中按钮的样式
instanceId String "" 组件实例ID,用于多实例区分,不传会自动生成

事件说明

事件名 说明 参数
send 点击获取验证码按钮时触发 { instanceId: string }
start 倒计时开始时触发 { instanceId: string }
end 倒计时结束时触发 { instanceId: string }

方法说明

方法名 说明 参数 返回值
start() 开始倒计时
stop() 停止倒计时
reset() 重置倒计时
getStatus() 获取当前状态 { isCounting: boolean, remaining: number, instanceId: string }

使用示例

javascript 复制代码
Page({
  data: {
    // ...
  },
  
  onSendVerifyCode(e) {
    // 发送验证码请求
    wx.request({
      url: 'your-api-url',
      success: () => {
        // 请求成功后开始倒计时
        this.selectComponent('#verifyCode').start();
      }
    });
  }
});

注意事项

组件会自动处理倒计时过程中的状态切换

倒计时过程中按钮会被禁用

组件销毁时会自动清理定时器

支持多个实例同时使用,每个实例都有唯一的instanceId

倒计时时间必须大于0,否则会自动设置为60秒

样式定制

可以通过 buttonStyle 和 disabledStyle 属性来自定义按钮样式,支持所有CSS属性。

javascript 复制代码
<countdown-verify 
  button-style="background-color: #007AFF; color: white; border-radius: 4px;"
  disabled-style="background-color: #999999; color: white;"
/>

完整代码

js

javascript 复制代码
// components/countdown-verify/countdown-verify.js
Component({
  properties: {
    // 倒计时总时长(秒)
    seconds: {
      type: Number,
      value: 60,
      observer: function (newVal) {
        if (newVal <= 0) {
          console.warn("倒计时时间必须大于0");
          this.setData({ seconds: 60 });
        }
      },
    },
    // 按钮默认文字
    buttonText: {
      type: String,
      value: "获取验证码",
    },
    // 禁用状态下的文字格式
    countdownFormat: {
      type: String,
      value: "剩余%s秒",
    },
    // 按钮样式
    buttonStyle: {
      type: String,
      value: "",
    },
    // 禁用状态按钮样式
    disabledStyle: {
      type: String,
      value: "background-color: #cccccc; color: #ffffff;",
    },
    // 实例ID,用于多实例区分
    instanceId: {
      type: String,
      value: "",
    },
  },

  data: {
    remaining: 0,
    isCounting: false,
    timer: null,
    displayText: "",
  },

  lifetimes: {
    attached() {
      // 生成唯一实例ID
      if (!this.properties.instanceId) {
        this.setData({
          instanceId:
            "countdown_" +
            Date.now() +
            "_" +
            Math.random().toString(36).substr(2),
        });
      }
      this.updateDisplayText();
    },
    detached() {
      this.clearTimer();
    },
  },
  // 监听倒计时和是否正在倒计时,更新显示文本
  observers: {
    "remaining, isCounting": function (remaining, isCounting) {
      this.updateDisplayText();
    },
  },

  methods: {
    // 更新显示文本
    updateDisplayText() {
      const text = this.data.isCounting
        ? this.properties.countdownFormat.replace("%s", this.data.remaining)
        : this.properties.buttonText;
      this.setData({ displayText: text });
    },

    // 开始倒计时
    start() {
      if (this.data.isCounting) {
        console.warn("倒计时正在进行中");
        return;
      }

      this.clearTimer();

      this.setData({
        isCounting: true,
        remaining: this.properties.seconds,
      });

      this.data.timer = setInterval(() => {
        const remaining = this.data.remaining - 1;
        if (remaining <= 0) {
          this.stop();
          return;
        }
        this.setData({ remaining });
      }, 1000);

      this.triggerEvent("start", { instanceId: this.data.instanceId });
    },

    // 停止倒计时
    stop() {
      this.clearTimer();
      this.setData({
        isCounting: false,
        remaining: 0,
      });
      this.triggerEvent("end", { instanceId: this.data.instanceId });
    },

    // 清除定时器
    clearTimer() {
      if (this.data.timer) {
        clearInterval(this.data.timer);
        this.data.timer = null;
      }
    },

    // 按钮点击事件
    handleTap() {
      if (!this.data.isCounting) {
        this.triggerEvent("send", { instanceId: this.data.instanceId });
      }
    },

    // 重置倒计时
    reset() {
      this.stop();
    },

    // 获取当前状态
    getStatus() {
      return {
        isCounting: this.data.isCounting,
        remaining: this.data.remaining,
        instanceId: this.data.instanceId,
      };
    },
  },
});

wxml

xml 复制代码
<!-- components/countdown-verify/countdown-verify.wxml -->
<button style="{{isCounting ? disabledStyle : buttonStyle}}" disabled="{{isCounting}}" bind:tap="handleTap" aria-label="{{isCounting ? '倒计时中' : buttonText}}" data-instance-id="{{instanceId}}">
    {{displayText}}
</button>

wxss

xml 复制代码
/* components/countdown-verify/countdown-verify.wxss */
button {
  margin: 0;
  padding: 0;
  border: none;
  background: none;
  font-size: 28rpx;
  line-height: 1.5;
  text-align: center;
  border-radius: 8rpx;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  min-width: 180rpx;
  height: 80rpx;
  display: flex;
  align-items: center;
  justify-content: center;
}

button[disabled] {
  opacity: 0.6;
}
button::after {
  border: none;
}

json

xml 复制代码
{
  "component": true,
  "usingComponents": {}
}
相关推荐
程序员王天12 分钟前
Uniapp 自定义TabBar + 动态菜单实现教程(Vuex状态管理详解)
微信小程序·uni-app
帅次2 小时前
Flutter Expanded 与 Flexible 详解
android·flutter·ios·小程序·webview
kidding7232 小时前
微信小程序怎么分包步骤(包括怎么主包跳转到分包)
前端·微信小程序·前端开发·分包·wx.navigateto·subpackages
低代码布道师4 小时前
加油站小程序实战教程12显示会员信息
低代码·小程序·云开发
码起来呗5 小时前
基于Spring Boot+微信小程序的智慧农蔬微团购平台-项目分享
spring boot·后端·微信小程序
白飞飞6 小时前
原生小程序工程化指北:从混乱到规范的进化之路
前端·vue.js·微信小程序
换日线°9 小时前
微信小程序文字混合、填充动画有效果图
css·微信小程序
hmywillstronger10 小时前
【ESP32】【微信小程序】MQTT物联网智能家居案例
物联网·微信小程序·智能家居
清晨細雨11 小时前
uniapp微信小程序:WIFI设备配网之TCP/UDP开发AP配网
前端·物联网·小程序·uni-app