网易云---手机验证码登录

5.3

5.3.0 写在前面

之前写扫码登录的时候对于什么时候clear那个发送请求获取二维码当前状态的定时器timer,只考虑了两种情况,现在再完善一下,再添加一种情况,就是路由的跳转:

  • 关闭 Dialog弹窗
  • 二维码状态 :失效或者登录成功/失败
  • 路由的跳转 :只要是从 /logincode 跳转出去,就应该清理 timer

那么如何实现路由跳转出去清理当前组件里的 timer 呢?

刚开始我的想法是:

  • 在父组件中设置变量 codeVisible,并且将其传递给子组件

  • 在他们的父组件中监听 $route,当路由发生跳转的时候改变codeVisible的值

  • 子组件的定时器中判断codeVisible,来决定是否清理 timer

    // 监听路由变化
    // 当路由从 /logincode 跳转到 /loginphone 或/register 将loginVisible变成 false
      watch: {
        '$route' (to, from) {
          console.log(from.path)
          // 下面的数据传送到子组件会有延迟
          // if (from.path === '/logincode') {
          //   console.log('从扫码页跳转出去了')
          //   this.codeVisible = false
          // }
        }
      }
    

    但是!我发现这样的做法不起作用,使用Vue的浏览器工具我发现在父组件的值发生变化的时候,子组件的值还没有来得及变化,然后会有一个延迟,此时子组件已经被移除,跳转到了新的路由,然后timer还是没有清理掉。

最后我在扫码登录组件的 beforeDestroy周期,在销毁该组件之间将 codeVisible 置为 false,timer 也就清理掉了

beforeDestroy () {
    // 当前组件被销毁之前 将codeVisible设置为false 用于消除定时器
    this.codeVisible = false
  }

5.3.1 UI界面

在这里插入图片描述

5.3.2 页面逻辑分析和实现

半角二维码

  • 点击跳转到扫码登录的路由 => 路由跳转
  • hover 提示信息:扫码登录更安全

这里的提示信息使用的是组件库的 el-tooltip,对位置稍作了调整。

<!-- 左上角半角二维码 -->
    <div id="halfQR-container">
      <el-tooltip
      class="item"
      effect="dark"
      content="扫码登录更安全"
      placement="right-start"
      :offset="-110"
      >
        <router-link to="/logincode">
          <el-image
          style="width: 50px; height: 50px;"
          :src="halfQRUrl"
          fit="contain"
          ></el-image>
        </router-link>
      </el-tooltip>
    </div>

IMG

使用了组件库的 el-image,调整了一下位置

<!-- 图片 -->
    <div class="block" style="margin:20px 0">
      <el-image
      fit="cover"
      style="width: 70%;position: relation; left: 50%; transform: translateX(-50%)"
      :src="phoneImgUrl"
      >
        <div slot="placeholder" class="image-slot">
          加载中<span class="dot">...</span>
        </div>
      </el-image>
    </div>

表单

  • 表单添加了验证,对电话号码添加了正则表达式来验证是否有效

    • 当电话号码有效时,后面的获取验证码按钮才会取消 disabled ,否则无法发送验证码,主要是监听手机号

      watch: {
          // 监听手机号 改变获取验证码按钮状态
          'ruleForm.phoneNumber': function (value) {
            const reg = /^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$/
            const val = reg.test(value)
            if (val) {
              this.attcode = false
            } else {
              this.attcode = true
            }
          }
        }
      
    • 点击发送验证码按钮,该按钮消失,取而代之的是 60s 的倒计时

      // 发送验证码
          async getCode () {
            // 调用 sendCode 发送验证码
            const sendCodeData = await sendCode(this.ruleForm.phoneNumber)
            if (sendCodeData.code !== 200) this.successSendMsg()
            // 修改页面样式
            const timer = setInterval(() => {
              this.codeSec = this.codeSec - 1
              this.codeMsg = this.codeSec + 's后重试'
              this.showBtn = false
              if (this.codeSec === 0) {
                clearInterval(timer)
                this.codeSec = 60
                this.showBtn = true
              }
            }, 1000)
          }
      
  • 验证码也添加了正则表达式来验证是否是四位

  • 监听密码,当4位的时候自动请求并且登录

    watch: {
        'ruleForm.phoneCode': async function (code) {
          if (code.length === 4) {
            // 自动请求并且登录
            const { data: byCodeData } = await byCode(this.ruleForm.phoneNumber, this.ruleForm.phoneCode)
            console.log(byCodeData)
            if (byCodeData.code === 200) {
              this.successLoginMsg()
              // 保存信息到 Vuex 跳转页面
            }
          }
        }
      }
    

奇奇怪怪

当验证码失败的时候我收到了状态码为503的返回数据,成功的时候是200,主要是这个503控制台报错让我十分难受

登录成功后(扫码和手机号)

  • 登录成功后打算将账户信息都存放在 Vuex 中
  • 由于扫码和手机号验证码端(之后别的组件也有可能要使用)都会使用到相同的方法来更新Vuex中的state数据,于是打算学习一下 Mixin 混入来达到代码更好的复用。
  • 待更…

5.3.3 源码

github地址:CloudMusic-vue2

LoginByPhoneNumber.vue

<template>
  <div id="login-phone-container">
    <!-- 左上角半角二维码 -->
    <div id="halfQR-container">
      <el-tooltip
      class="item"
      effect="dark"
      content="扫码登录更安全"
      placement="right-start"
      :offset="-110"
      >
        <router-link to="/logincode">
          <el-image
          style="width: 50px; height: 50px;"
          :src="halfQRUrl"
          fit="contain"
          ></el-image>
        </router-link>
      </el-tooltip>
    </div>
    <!-- 图片 -->
    <div class="block" style="margin:20px 0">
      <el-image
      fit="cover"
      style="width: 70%;position: relation; left: 50%; transform: translateX(-50%)"
      :src="phoneImgUrl"
      >
        <div slot="placeholder" class="image-slot">
          加载中<span class="dot">...</span>
        </div>
      </el-image>
    </div>
    <!-- 输入框 -->
    <div id="form-container" style="margin:10px">
      <!-- <el-input placeholder="请输入手机号" v-model="phoneNumber" class="input-with-select">
        <i slot="prefix" class="el-input__icon el-icon-mobile-phone"></i>
      </el-input> -->
      <el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="auto" class="login-ruleFrom" style="margin:0 15px">
        <el-form-item label="" prop="phoneNumber">
          <el-input v-model="ruleForm.phoneNumber" placeholder="请输入手机号">
            <i slot="prefix" class="el-input__icon el-icon-mobile-phone"></i>
          </el-input>
          <el-button
          size="mini"
          class="getCodeButton"
          :disabled="attcode"
          v-if="showBtn"
          @click="getCode"
          >获取验证码</el-button>
          <el-button
          class="getCodeButton"
          plain
          disabled
          v-else
          >{{codeMsg}}</el-button>
        </el-form-item>
        <el-form-item label="" prop="phoneCode">
          <el-input v-model="ruleForm.phoneCode" placeholder="请输入验证码">
            <i slot="prefix" class="el-input__icon el-icon-lock"></i>
          </el-input>
        </el-form-item>
        <el-form-item label="" prop="type" style="margin-top:-10px">
          <el-switch v-model="ruleForm.autoLogin" active-text="自动登录" ></el-switch>
        </el-form-item>
        <el-form-item style="margin-bottom:-20px">
          <el-button type="primary" @click="submitForm('ruleForm')" style="width:100%;">登录</el-button>
          <router-link to="/register" class="other-way"> 注册 </router-link>
        </el-form-item>
      </el-form>
    </div>

  </div>
</template>

<script>
import { byCode, sendCode } from '@/api/LoginAndRegister/loginByPhone.js'

export default {
  data () {
    return {
      // 获取验证码按钮是否禁用
      attcode: true,
      // 获取验证码按钮是否展示
      showBtn: true,
      codeMsg: '获取验证码',
      // 倒计时
      codeSec: 60,
      halfQRUrl: require('@/assets/images/halfQR.png'),
      phoneImgUrl: require('@/assets/images/phoneImg.png'),
      ruleForm: {
        phoneNumber: '',
        phoneCode: '',
        autoLogin: false
      },
      rules: {
        phoneNumber: [
          { required: true, message: '请输入手机号', trigger: 'blur' },
          { pattern: /^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$/, message: '请正确填写您的手机号码', trigger: 'blur' }
        ],
        phoneCode: [
          { required: true, message: '请输入验证码', trigger: 'blur' },
          { pattern: /^[0-9]{4}$/, message: '请填写有效的验证码', trigger: 'blur' }
        ]
      }
    }
  },
  watch: {
    // 监听手机号 改变获取验证码按钮状态
    'ruleForm.phoneNumber': function (value) {
      const reg = /^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$/
      const val = reg.test(value)
      if (val) {
        this.attcode = false
      } else {
        this.attcode = true
      }
    },
    'ruleForm.phoneCode': async function (code) {
      if (code.length === 4) {
        // 自动请求并且登录
        const { data: byCodeData } = await byCode(this.ruleForm.phoneNumber, this.ruleForm.phoneCode)
        console.log(byCodeData)
        if (byCodeData.code === 200) {
          this.successLoginMsg()
          // 保存信息到 Vuex 跳转页面
        }
      }
    }
  },
  methods: {
    // 错误提示信息
    errorMsg () {
      this.$message({
        showClose: true,
        message: '电话或验证码错误!',
        type: 'error'
      })
    },
    // 短信发送成功提示信息
    successSendMsg () {
      this.$message({
        showClose: true,
        message: '短信发送成功!',
        type: 'success'
      })
    },
    // 登录成功提示信息
    successLoginMsg () {
      this.$message({
        showClose: true,
        message: '登录成功!',
        type: 'success'
      })
    },
    // 提交登录表单
    async submitForm (formName) {
      console.log(this.ruleForm.phoneNumber, this.ruleForm.phonePassword, this.ruleForm.autoLogin)
      this.$refs[formName].validate(async (valid) => {
        if (valid) {
          // 发送请求
          const byCodeData = await byCode(this.ruleForm.phoneNumber, this.ruleForm.phoneCode)
          if (byCodeData.code === 200) {
            this.successLoginMsg()
            // 保存信息到 Vuex 跳转页面
          } else {
            this.errorMsg()
          }
        } else {
          console.log('error submit!!')
          return false
        }
      })
    },
    // 发送验证码
    async getCode () {
      // 调用 sendCode 发送验证码
      const sendCodeData = await sendCode(this.ruleForm.phoneNumber)
      if (sendCodeData.code !== 200) this.successSendMsg()
      // 修改页面样式
      const timer = setInterval(() => {
        this.codeSec = this.codeSec - 1
        this.codeMsg = this.codeSec + 's后重试'
        this.showBtn = false
        if (this.codeSec === 0) {
          clearInterval(timer)
          this.codeSec = 60
          this.showBtn = true
        }
      }, 1000)
    }
  }
}
</script>

<style lang="less" scoped>
  #halfQR-container{
    position: absolute;
    top: 0;
    left: 0;
  }
  .el-select{
    width: 90px;
  }
  .input-with-select .el-input-group__prepend {
    background-color: #fff;
  }
  .other-way{
    display: inline-block;
    margin: 10px 0 25px 0;
    width: 100%;
    text-align: center;
    padding-right: 0;
    font-size: 14px;
    line-height: 28px;
    color: rgba(0,0,0,0.80);
    text-decoration-line:underline;
  }
  .getCodeButton{
    box-sizing: border-box;
    position: absolute;
    height: 100%;
    right: 0;
    border-radius: 0;
  }
</style>

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值