vue实现手机验证码登录

登录逻辑:

1 验证手机号码输入框,分别判断以下情况并作出弹窗警告
(1:是否为空
(2:是否为11位数字
(3:是否是13,15, 17, 18开头的正确手机号码

2 输入框下面添加一个获取验证码的按钮,默认为关闭不可点击,
点击后,开启一个定时器setInterval,然后发送一个ajax请求给后台,把手机号传给后台,让后台去发送短信

在验证上面3种情况之后,得到为正确手机号码后
再将验证码按钮设置为可点击

3 验证验证码的输入框,分别判断以下情况并作出弹窗警告
1:是否为空
2:是否为6位数字

4 验证座位号的输入框,分别判断以下情况并作出弹窗警告
1:是否为空
2:

勾选华夏航空娱乐系统安全须知

原文:https://blog.csdn.net/weixin_41818920/article/details/82290511

手机注册验证逻辑是这样的:
首先要找短信服务商如:梦网、云信使、互亿无线等等申请短信发送接口。
网站实现流程如下:
第一步:用户注册时输入手机号,网站首先要通过JS或者ajax+php验证这个号码是不是正确的手机号。
第二步:用户点击发送手机验证码,通过ajax把手机号传到php,这时php生成一个随机的验证码保存在session中,然后通过短信接口把这个验证码发送到这个手机号中。
第三步:用户输入手机收到的验证码注册。网站用session中的验证码和用户输入的验证码比较。


平时我们在项目中进行注册等的时候,会经常用到短信验证的功能,但是现在现在很多短信验证都是存在下面几个问题,例如短信验证时间为60s的时候,

  1. 当点击完按钮时,倒计时还没到60s过完时,刷新浏览器,验证码按钮又可以重新点击
  2. 当点击按钮倒计时开始,例如在50s的时候我关闭了浏览器,过了5s后,我在打开,此时时间倒计时的时间应该是45s左右,但是当重新打开浏览器的时候,按钮又可以重新点击了

为了解决上面的两个问题,就需要把时间都写到localstorage里面去,当打开页面的时候,就去localstorage里面去取,
https://blog.csdn.net/qq_39581763/article/details/81739428

设置反向代理
https://blog.csdn.net/weixin_43067157/article/details/82079792?utm_source=blogxgwz0

devServer: {
    // 设置代理
    proxy: {
      '/v1': {
        target: 'http://localhost:8080/', // 域名
        ws: true, // 是否启用websockets
        changOrigin: true, // 开启代理:在本地会创建一个虚拟服务端,然后发送请求的数据,并同时接收请求的数据,这样服务端和服务端进行数据的交互就不会有跨域问题
        pathRewrite: {
          '^/v1': '/'
        }
      }
    }
  },

element ui 的表单验证

H5学习之路-手机短信验证码的实现
https://blog.csdn.net/qiyongkang520/article/details/55007040
vue 实现通过手机发送验证码注册
https://www.jianshu.com/p/3a96636e7242
vue做一个有验证码的登陆页面和注册页面,敲回车登陆
https://blog.csdn.net/hani_wen/article/details/81545319
关于vue.js element ui 表单验证 this.$refs[formName].validate()的问题
https://blog.csdn.net/qq_41894865/article/details/80476736

一、element ui 表单验证源码

<templete>
    <el-main>
        <el-form :model="ReginForm" ref="ReginForm" :rules="rule" class="regform" label-width="0">
            <h3 class="login-text">手机注册</h3>
            <el-form-item prop="tel">
                <el-input type="text" v-model.number="ReginForm.tel" placeholder="手机号码">
                </el-input>
            </el-form-item>
            <el-form-item prop="password">
                <el-input type="password" v-model="ReginForm.password" placeholder="密码">
                </el-input>
            </el-form-item>
            <div>
                <input class="auth_input" type="text" v-model="verification" placeholder="输入验证码" />
                <span v-show="sendAuthCode" class="auth_text auth_text_blue" @click="getAuthCode">获取验证码</span>
                <span v-show="!sendAuthCode" class="auth_text"> <span class="auth_text_blue">{{auth_time}} </span>
                    秒之后重新发送验证码</span>
            </div>
            <el-form-item>
                <el-button type="success" class="submitBtn" round @click.native.prevent="submit" :loading="logining">
                    注册
                </el-button>
                <hr>
                <p>已经有账号,马上去<span class="to" @click="tologin">登录</span></p>
            </el-form-item>
        </el-form>
    </el-main>
</template>
<script>
export default {
  data() {
    let confirmpasswordCheck = (rule, value, callback) => {
      if (value === "") {
        return callback(new Error("密码是必须的"));
      } else {
        return callback();
      }
    };
    let telCheck = (rule, value, callback) => {
      if (value === "") {
        return callback(new Error("电话号码是必须的"));
      } else if (!Number.isInteger(value)) {
        return callback(new Error("电话号码必须是数字"));
      } else if (value.toString().length !== 11) {
        return callback(new Error("电话号码必须是11位数字"));
      } else {
        callback();
      }
    };
    return {
      ReginForm: {
        password: "",
        tel: ""
      },
      logining: false,
      sendAuthCode: true,
      /*布尔值,通过v-show控制显示‘获取按钮’还是‘倒计时’ */
      auth_time: 0,
      /*倒计时 计数器*/
      verification: "", //绑定输入验证码框框
      rule: {
        password: [
          {
            required: true,
            message: "密码是必须的!",
            trigger: "blur"
          }
        ],
        tel: [
          {
            required: true,
            validator: telCheck,
            trigger: "blur"
          }
        ]
      }
    };
  },
  methods: {
    //   验证
    getAuthCode: function() {
      const verification = this.ReginForm.tel;

      const url = " ";
      console.log("url", url);
      this.$http.get(url).then(
        function(response) {
          console.log("请求成功", response);
        },
        function(error) {
          console.log("请求失败", error);
        }
      );
      this.sendAuthCode = false;
      //设置倒计时秒
      this.auth_time = 30;
      var auth_timetimer = setInterval(() => {
        this.auth_time--;
        if (this.auth_time <= 0) {
          this.sendAuthCode = true;
          clearInterval(auth_timetimer);
        }
      }, 1000);
    },
    // 封装注册发送请求方法
    thisAjax() {
      const passwordData = this.ReginForm.password;
      const phoneData = this.ReginForm.tel;
      const mCodeData = this.verification;

      //   手机注册
      //emulateJSON:true设置后post可跨域

      const url = " 填接口";
      this.$http
        .post(
          url,
          {
            填传入的参数
          },
          {
            emulateJSON: true
          }
        )
        .then(
          function(response) {
            //登录后跳转的页面
            this.$router.push("/");
          },
          function(error) {
            alert("请求失败", error);
          }
        );
    },
    // ...
    submit() {
      this.$refs.ReginForm.validate(valid => {
        if (valid) {
          this.logining = true;
          this.thisAjax();
          console.log("开始写入后台数据!");
        } else {
          console.log("submit err");
        }
      });
    },
    reset() {
      this.$refs.ReginForm.resetFields();
    },
    tologin() {
      //已经注册过跳转到登入界面
      this.$router.push("/phoneLogin");
    }
  }
};
</script>
    <style>
.regform {
  margin: 20px auto;
  width: 310px;
  background: #fff;
  box-shadow: 0 0 10px #b4bccc;
  padding: 30px 30px 0 30px;
  border-radius: 25px;
}

.submitBtn {
  width: 65%;
}

.to {
  color: #fa5555;
  cursor: pointer;
}

.auth_input {
  width: 140px;
  height: 38px;
  margin-bottom: 20px;
  border: 1px solid #dcdfe6;

  /* color:red; */
  padding-left: 10px;
  border-radius: 8%;
}

.regform[data-v-92def6b0] {
  width: 370px;
  min-height: 440px;
}

.login-text {
  text-align: center;
  margin-bottom: 20px;
}
</style>

30s倒计时

<button class="close_tel" v-show="show" @click="getCode">获取验证码</button>
<button class="close_tel2" v-show="!show" > 重新获取({{count}}s)</button>
getCode() {
      const TIME_COUNT = 30
      if (!this.timer) {
        this.count = TIME_COUNT
        this.show = false
        this.timer = setInterval(() => {
          if (this.count > 0 && this.count <= TIME_COUNT) {
            this.count--
          } else {
            this.show = true
            clearInterval(this.timer)
            this.timer = null
          }
        }, 1000)
      }
    },

二、自己写

<template>
  <div>
    <div class="login">
      <div class="logo">
        <div>
          <img src="../assets/images/logo.png" alt>
        </div>
      </div>
      <p class="welcome">
        <span>欢迎乘坐</span>
        <span>G5XXXX</span>
        <span>航班,</span>
        <span>重庆-贵阳</span>
      </p>
      <p class="info">为了给您更好的服务,请填写以下信息:</p>
      <form :model="ReginForm" ref="ReginForm">
        <input type="tel" class="phone" placeholder="手机号" v-model="loginForm.tel">
        <input class="phone" type="number" placeholder="验证码" v-model="loginForm.msg">
        <button class="close_tel" v-show="show" @click="getCode">获取验证码</button>
        <button class="close_tel2" v-show="!show" > 重新获取({{count}}s)</button>
        <input type="text" class="phone" placeholder="座位号" v-model="loginForm.seat">
        <div class="check-item">
          <cube-checkbox v-model="loginForm.check" :option="option">华夏航空娱乐系统安全须知</cube-checkbox>
        </div>
        <cube-button class="subLogin" @click="submit">登录</cube-button>
      </form>
    </div>
    <p class="online">在线</p>

    <!-- <Count  v-bind:num="num" ></Count>-->
    <!-- <Menu></Menu> -->
  </div>
</template>

<script>
// import { mapMutations } from 'vuex'

// import Count from '../components/shop/Count.vue'
// import Menu from '../components/common/Menu.vue'

export default {
  name: 'login',
  data() {
    return {
      show: true,
      count: '',
      timer: null,
      check: '',
      // num: 10,
      loginForm: {
        tel: '',
        seat: '',
        check: false,
        msg: ''
      },
      option: {
        label: 'Option Checkbox',
        value: 'optionValue',
        disabled: false
      }
    }
  },
  methods: {
    getCode() {
      const TIME_COUNT = 30
      if (!this.timer) {
        this.count = TIME_COUNT
        this.show = false
        this.timer = setInterval(() => {
          if (this.count > 0 && this.count <= TIME_COUNT) {
            this.count--
          } else {
            this.show = true
            clearInterval(this.timer)
            this.timer = null
          }
        }, 1000)
      }
    },
    submit() {
      var myreg = /^(((13[0-9]{1})|(15[0-9]{1})|(18[0-9]{1})|(17[0-9]{1}))+\d{8})$/ // 验证是不是以13,15,18,17开头的数字
      var num = /^\d{6}$/ // 验证是否6位数字
      if (this.loginForm.tel === '') {
        alert('手机号不能为空!')
      } else if (this.loginForm.tel.length !== 11) {
        alert('请输入11位的手机号码!')
      } else if (!myreg.test(this.loginForm.tel)) {
        alert('请输入有效的手机号码!')
      } else if (this.loginForm.msg === '') {
        alert('请填写验证码!')
      } else if (!num.test(this.loginForm.msg)) {
        alert('请填写正确的验证码!')
      } else if (this.loginForm.seat === '') {
        alert('座位号不能为空!')
      } else if (this.loginForm.check === false) {
        alert('请确认勾选华夏航空娱乐系统安全须知!')
      } else {
        this.$router.push('/main')
      }
    }
  }
  // components: { Count, Menu }
}
</script>

<style scoped>
* {
  margin: 0;
  padding: 0;
}
input {
  flex: 1;
}
a {
  cursor: pointer;
}
.phone {
  width: 220px;
  display: block;
  margin: 0 auto;
  font-size: 16px;
  /* color: #666;     */
  outline: none;
  padding-top: 30px;
  border-left: none;
  border-right: none;
  border-top: none;
  border-bottom: 0.1px solid rgb(196, 194, 194);
  position: relative;
}
.close_tel {
  font-size: 12px;
  width: 100px;
  height: 23px;
  line-height: 25px;
  border-radius: 5px;
  background-color: rgb(86, 159, 255);
  color: white;
  position: absolute;
  right: 20%;
  top: 255px;
  outline: none;
  border: 0;
  font-weight: 400;
  cursor: pointer;
}
.close_tel2 {
  font-size: 12px;
  width: 100px;
  height: 23px;
  line-height: 25px;
  border-radius: 5px;
  background-color: rgb(211, 211, 211);
  color: white;
  position: absolute;
  right: 20%;
  top: 255px;
  outline: none;
  border: 0;
  font-weight: 400;
  cursor: pointer;
}
.login {
  padding-top: 50px;
  background-color: white;
  font-size: 16px;
}
.logo {
  width: 220px;
  /* border: #666 1px solid; */
  margin: 0 auto;
}
.logo img {
  display: block;
  width: 100%;
  height: auto;
}
.login p {
  font-size: 13px;
  width: 260px;
  text-align: center;
  margin: 0 auto;
}
.welcome {
  color: #338bff;
}
.check-item {
  width: 220px;
  margin: 10px auto;
  font-size: 12px;
  color: grey;
}
.info {
  color: grey;
  letter-spacing: 1.2px;
}
.phone {
  width: 220px;
  display: block;
  margin: 0 auto;
  font-size: 16px;
  /* color: #999;     */
  outline: none;
  padding-top: 30px;
  border-left: none;
  border-right: none;
  border-top: none;
  border-bottom: 0.1px solid rgb(196, 194, 194);
}

input {
  padding-bottom: 10px;
  font-weight: 700;
  color: #666;
  letter-spacing: 2px;
}
::-webkit-input-placeholder {
  /* WebKit, Blink, Edge */
  color: #999;
}
.subLogin {
  display: block;
  margin: 0 auto;
  width: 240px;
  height: 50px;
  margin-top: 40px;
  background-color: #338bff;
  color: white;
  border-radius: 10px;
  font-size: 18px;
  outline: none;
  border: 0;
  cursor: pointer;
  letter-spacing: 10px;
}
.online {
  width: 100%;
  margin: 0 auto;
  text-align: center;
  letter-spacing: 15px;
  color: rgb(180, 173, 173);
  position: fixed;
  bottom: 30px;
}
</style>

猜你喜欢

转载自blog.csdn.net/fengtingYan/article/details/88223903