wepy2 小程序 密码弹框 验证码弹框 模拟聚焦

需求:小程序中手机获取验证码后,自动弹出数字键盘,弹出输入验证码弹窗并且有光标闪烁效果

验证码弹窗组件:

<template>
<van-popup custom-style="border-radius:4px;height:460rpx;top:30%" show="{
   
   {showPayPwdInput}}" close-on-click-overlay="{
   
   {false}}" closeable bind:close="closeFn">
  <div class="code">
    <div class="input_main">
      <div class="input_tip">
        <p class="input_tip_tit">输入短信验证码</p>
        <span class="input_tip_content">验证码已发送至{
   
   {phoneNumber}}</span>
      </div>
      <div class="input_row" @tap="$emit('payFocus')">
        <div class="pwd_item" v-for="(item,index) in 4" :key="index" :class="{'get_focus':(value_length == index) && payFocus}">
          <div v-if="(value_length == index) && payFocus" class="cursor"></div>
          <div v-if="(value_length >= index-1)">{
   
   {val_arr[index]}}</div>
        </div>
      </div>
      <p v-if="isSendCode" class="input_code">{
   
   {time}}s后可重新获取</p>
        <p v-else class="forget_pwd" @tap="$emit('resend')">重新发送</p>
      
    </div>
  </div>
</van-popup>

</template>
<config>
{
  "navigationBarTitleText": "授权登录",
  "usingComponents": {
    "van-popup": "~@vant/popup/index",
  }
}
</config>>
<script>
import wepy from '@wepy/core';

wepy.component({
  props: {
    payFocus: {
      type: Boolean,
      default: () => {
        return []
      }
    },
    val_arr: {
      type: Array,
      default: () => {
        return []
      }
    },
    value_length: {
      type: String
    },
    showPayPwdInput: {
      type: Boolean,
      default: false
    },
    phoneNumber: {
      type: Number
    },
    countDown: {
      type: Number,
      default: 60
    }
  },
  data: {
    timeout: null,
    time: 60,
    isSendCode: true // 是否已经发送验证码
  },
  watch: {
    countDown(val) {
      if (val > 0) this.isSendCode = true
      if (val === 60) {
        this.timeDown(val)
      }
    }
  },
  methods: {
    closeFn() {
      this.$emit('closeFn', this.isSendCode ? this.time : null);
    },
    // 倒计时
    timeDown(time) {
      this.timeout = setInterval(() => {
        time -= 1;
        this.time = time;
        if (time <= 0) {
          this.time = 60;
          this.$emit('timeOver')
          this.isSendCode = false;
          clearInterval(this.timeout);
        }
      }, 1000);
    }

  }
});
</script>
<style lang="less" scoped>
.code {
  /* 模拟光标 */
  .cursor {
    width: 1px;
    height: 15px;
    background-color: rgba(0,159,252,1);
    animation: focus 0.7s infinite;
  }

  /* 光标动画 */

  @keyframes focus {
    from {
      opacity: 1;
    }

    to {
      opacity: 0;
    }
  }
}
/* 支付密码框聚焦的时候 */
.get_focus {
  border:1px solid rgba(0,159,252,1) !important;
}
.input_code{
  text-align: center;
  margin: 7rpx auto 7rpx;
  font-size: 24rpx;
  color: #BFBFBF;
}
/* 支付密码css start */
.input_main {
  padding: 19rpx 23rpx;
  margin: 0 auto;
  width: 570rpx;
  height: 394rpx;
  background-color: #fff;
  z-index: 9999;
  border-radius: 4px;
}

.input_tip {
  margin: 30rpx;
  font-size: 24rpx;
  color: #888;
}
.input_tip_tit{
  font-size:32rpx;
  font-weight:500;
  color:rgba(66,68,86,1);
  margin-bottom: 18rpx;
}
.input_tip_content{
  font-size:28rpx;
  font-weight:400;
  color:rgba(0,0,0,0.45);
}
/* 密码掩码模拟 */
.input_row {
  margin: 64rpx 30rpx;
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.input_row .pwd_item {
  margin: 0 10rpx;
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100rpx;
  width: 100rpx;
  border-radius:4rpx;
  border:1px solid rgba(204,204,204,1);
  position: relative;
}
.pwd_item:nth-child(1) {
  margin-left: 0;
}
.pwd_item:nth-last-of-type(1) {
  margin-right: 0;
}
.pwd_item text {
  width: 30rpx;
  height: 30rpx;
  border-radius: 30rpx;
  background-color: #555;
}
.forget_pwd {
  width: 100rpx;
  margin: 7rpx auto 7rpx;
  font-size: 24rpx;
  color: #009ffc;
}


</style>

关键:在父组件中隐藏一个数字输入框

<template>
  <div class="login">
    <div class="phoneLogin">
      <div class="phoneLogin-phoneInput">
        <i class="iconfont icon_jiedian"></i>
        <i class="iconfont icon-phone" style="font-size:30px"></i>
        <van-field
          value="{
   
   { phoneNumber }}"
          bind:input="inputPhone"
          maxlength="11"
          type="number"
          input-class="font32"
          clearable
          placeholder="请输入手机号"
        >
          <img slot="left-icon" src="~@/images/icon_phone.png" class="icon_phone" />
        </van-field>
      </div>
      <button 
        type="primary" 
        :disabled="isPhone" 
        class="phoneLogin-next" 
        :class="{ 'next-disabled' : isPhone }"
        @tap="showInputLayer"
      >下一步</button>
    </div>

    <code-panel
      @payFocus="payFocus = true"
      :value_length="value_length"
      :val_arr="val_arr"
      ref="codePanel"
      @resend="showInputLayer('resend')"
      @timeOver="countDown = null"
      @closeFn="closeFn"
      :showPayPwdInput="showPayPwdInput"
      @inputOver="codeFn"
      :payFocus="payFocus"
      :countDown="countDown"
      :phoneNumber="phoneNumber"
    />
    <input
      :val_arr="val_arr"
      :val_length="val_length"
      class="input_control"
      focus="{
   
   {payFocus}}"
      type="number"
      bind:blur="payFocus = false"
      bind:input="inputPwd"
      maxlength="4"
      >
  </div>
</template>
<script>
import wepy from '@wepy/core';
import { getLogin, sendCode, dologin } from '@/api/login';
import tip from '@/utils/tip';
wepy.page({
  data: {
    val_arr: [],
    value_length: 0,
    payFocus: false,
    timeout: false, // 是否登录超时
    agreementType: 'agreement', // 货六六协议 agreement 用户隐私协议 userAgreement
    isFive: true, // 是否过了5秒
    confirmTxt: '我知道了',
    isviewDeal: false, // 查看协议
    isPhone: true,
    phoneNumber: '', // 用户手机号
    showPayPwdInput: false, // 是否展示验证码输入框
    isPhoneLogin: false, // 是否为手机号登录
    countDown: null, // 倒计时
    backurl: '/pages/personal/index' // 返回上一级
  },
  onLoad(options) {
    if (options.timeout) {
      this.timeout = true;
    }
  },
  onShow() {
    const app = getApp();
    let _url = wx.getStorageSync('backUrl');
    if (_url) this.backurl = _url
    wx.login({
      success (res) {
        if (res.code) {
          app.appCode = res.code;
        } else {
          console.log('登录失败!' + res.errMsg)
        }
      }
    })
  },
  watch: {
    value_length(val) {
      if (val === 4) {
          // 设定延时事件处理
        this.codeFn(this.val_arr)
      }
    }
  },
  methods: {
    inputPwd: function(e) {
      // 设置空数组用于明文展现
      let val_arr = [];
      // 获取当前输入框的值
      let now_val = e.$wx.detail.value
      // 遍历把每个数字加入数组
      for (let i = 0; i < 4; i++) {
        val_arr.push(now_val.substr(i, 1))
      }
      this.val_arr = val_arr;
      this.value_length = e.$wx.detail.value.length
    },
 
    codeFn(val) {
      const app = getApp();
      // 验证码输入完成后 执行方法
      let params = {
        login: Number(this.phoneNumber),
        code: Number(val.join('')),
        platform: 'mini-program',
        type: 1,
        mpcode: app.appCode
      };
      dologin(params, {
        'content-type': 'application/x-www-form-urlencoded'
      }).then(({ data: { ret, data, msg } }) => {
        if (ret === 0) {
          this.showPayPwdInput = false;
          wx.setStorageSync('userCenter', data);
          wx.setStorageSync('token', data.token);
          if (this.timeout) {
            // 登录超时 返回上个页面
            wx.navigateBack();
          } else {
            wx.reLaunch({ url: this.backurl });
          }
        } else {
          tip.toast(msg, '', 'none');
        }
      });
    },

    inputPhone(e) {
      let value = e.$wx.detail;
      if (value.indexOf(1) === 0 && value.length === 11) {
        this.isPhone = false;
      } else {
        this.isPhone = true;
      }
      this.phoneNumber = value;
    },
    showInputLayer(type = '') {
      if (
        this.phoneNumber === '' ||
        this.phoneNumber.length !== 11 ||
        this.phoneNumber.indexOf(1) !== 0
      ) {
        tip.toast('手机号格式不正确', '', 'none');
        return;
      }
      if (this.countDown && type !== '') {
        this.showPayPwdInput = true;
        return;
      }
      sendCode(
        { mobile: this.phoneNumber },
        { 'content-type': 'application/x-www-form-urlencoded' }
      ).then(({ data: { ret, data, msg } }) => {
        if (ret === 0) {
          if (!this.countDown) this.countDown = 60;
          this.showPayPwdInput = true;
          this.payFocus = true;
        } else {
          tip.toast(msg, '', 'none');
        }
      });
    },
    /**
     * 获取焦点
     */
    getFocus: function() {
      this.payFocus = true;
    },
    getPhoneNumber(e) {
      let self = this;
      if (e.$wx.detail.errMsg === 'getPhoneNumber:ok') {
        wx.checkSession({
          success () {
            console.log('登录状态')
            self.loginFn(e)
          },
          fail () {
            console.log('重新登录')
            // session_key 已经失效,需要重新执行登录流程
            wx.login({
              success (res) {
                if (res.code) {
                  self.loginFn(e, res.code)
                } else {
                  console.log('登录失败!' + res.errMsg)
                }
              }
            })
          }
        })
      }
    }
  }
});
</script>
<config>
{
  "navigationBarTitleText": "授权登录",
  "usingComponents": {
    "van-button": "~@vant/button/index",
    "van-field": "~@vant/field/index",
    "van-icon": "~@vant/icon/index",
    "code-panel": "~@/components/code-panel",
    "van-popup": "~@vant/popup/index",
    'deal': "./deal"

  }
}
</config>>

<style lang="less" scoped>
@base: 2rpx;
@import '~@/less/px2rpx.less';
.gray {
  color: rgba(191, 191, 191, 1) !important;
}
/* 文本输入框位置: 设置到左边隐藏 */
.input_control {
  position: relative;
  text-indent: -999em;
  left: -100%;
}
.icon_phone{
  width:48rpx;
  height:48rpx;
  margin-right: 16rpx;
}
.font32{
  font-size: 32rpx;
}
.login {
  .dealBox {
    width: 624rpx;
    background: rgba(255, 255, 255, 1);
    border-radius: 16rpx;
    &-confirm {
      border-top: 1px rgba(0, 0, 0, 0.09) solid;
      height: 96rpx;
      display: flex;
      align-items: center;
      justify-content: center;
      color: #009ffc;
    }
  }
  .logo {
    width: 308rpx;
    display: block;
    margin: 126rpx auto 100rpx;
  }
  padding: 0 48rpx;
  .blue {
    color: #009ffc;
  }
  button {
    width: 622rpx;
    font-size: 36rpx;
    font-weight: 400;
    letter-spacing: 1px;
  }
  &-deal {
    font-size: 24rpx;
    color: #8c8c8c;
    text-align: center;
  }
  &-phone {
    background: rgba(255, 255, 255, 1);
    border-radius: 4px;
    color: #8c8c8c;
    margin: 32rpx auto;
  }
  .phoneLogin {
    &-next {
      width: 100%;
      justify-content: center;
      align-items: center;
      background: #009FFC !important;
      margin: 32rpx auto;
    }
    .next-disabled {
      background-color: #9BDAFF !important;
    }
    &-phoneInput {
      border-bottom: 1rpx #e5e5e5 solid;
    }
  }
}
</style>

完整代码已附上,需要请自取

也可以扫码体验

猜你喜欢

转载自blog.csdn.net/z00001993/article/details/107101296
今日推荐