首页 > 其他分享 >vue3适配移动端的登录实现

vue3适配移动端的登录实现

时间:2023-04-03 17:46:42浏览次数:38  
标签:__ const 登录 form color 适配 rem value vue3

<script lang="ts" setup>
import { ref } from 'vue'

const PHONE_NUMBER_REGEX = /^1[0-9]{10}$/
const VERIFICATION_CODE_REGEX = /^[0-9]{6}$/
const LOGIN_ERROR_MESSAGE = '登录失败,请检查网络连接并重试'
const GENERATE_CODE_ERROR_MESSAGE = '无法生成验证码,请检查网络连接并重试'

const phoneNumber = ref('')
const verificationCode = ref('')
const countdown = ref(0)
const isLoggingIn = ref(false)
const errorMessage = ref('')

const handleSubmit = async () => {
  // 格式验证
  if (!PHONE_NUMBER_REGEX.test(phoneNumber.value)) {
    errorMessage.value = '手机号格式不正确'
    return
  }

  if (!VERIFICATION_CODE_REGEX.test(verificationCode.value)) {
    errorMessage.value = '验证码格式不正确'
    return
  }

  isLoggingIn.value = true
  errorMessage.value = ''

  try {
    // 并行执行发送登录请求和验证验证码请求
    const [loginResult, verifyResult] = await Promise.all([
      fetch(`https://example.com/api/login?phone=${phoneNumber.value}&code=${verificationCode.value}`),
      fetch(`https://example.com/api/verify?phone=${phoneNumber.value}&code=${verificationCode.value}`),
    ])

    if (!loginResult.ok || !verifyResult.ok) {
      errorMessage.value = LOGIN_ERROR_MESSAGE
      return
    }

    // 登录成功后重置表单
    phoneNumber.value = ''
    verificationCode.value = ''
  }
  catch (error) {
    errorMessage.value = LOGIN_ERROR_MESSAGE
    return
  }
  finally {
    isLoggingIn.value = false
  }
}

const generateCode = async () => {
  // 格式验证
  if (!PHONE_NUMBER_REGEX.test(phoneNumber.value)) {
    errorMessage.value = '手机号格式不正确'
    return
  }
  // 先禁用按钮
  countdown.value = 60
  const timer = setInterval(() => {
    countdown.value -= 1
    if (countdown.value === 0)
      clearInterval(timer)
  }, 1000)

  try {
    const response = await fetch(`https://example.com/api/sendcode?phone=${phoneNumber.value}`)
    if (!response.ok)
      throw new Error(GENERATE_CODE_ERROR_MESSAGE)
  }
  catch (error) {
    errorMessage.value = GENERATE_CODE_ERROR_MESSAGE // error.message
    countdown.value = 0
    clearInterval(timer)
  }
}
</script>

<template>
  <div class="form">
    <h3 class="form__title">
      登录
    </h3>
    <div class="form__group">
      <label class="form__label" for="phone">电话</label>
      <input id="phone" v-model.trim="phoneNumber" class="form__input" type="tel" :class="{ 'is-invalid': errorMessage && !PHONE_NUMBER_REGEX.test(phoneNumber) }">
      <!-- <div v-if="errorMessage && !PHONE_NUMBER_REGEX.test(phoneNumber)" class="form__error">
        手机号格式不正确
      </div> -->
    </div>
    <div class="form__group">
      <label class="form__label" for="verification-code">验证码</label>
      <div class="form__group form__group--inline">
        <input
          id="verification-code"
          v-model.trim="verificationCode"
          class="form__input form__input--inline"
          type="text"
          :class="{ 'is-invalid': errorMessage && !VERIFICATION_CODE_REGEX.test(verificationCode) }"
        >
        <button
          class="form__button form__button--inline"
          type="button"
          :disabled="countdown > 0"
          @click="generateCode"
        >
          {{ countdown > 0 ? `${countdown}秒后可重新获取` : '获取验证码' }}
        </button>
      </div>
      <!-- <div v-if="errorMessage && !VERIFICATION_CODE_REGEX.test(verificationCode)" class="form__error">
        验证码格式不正确
      </div> -->
    </div>
    <div v-if="errorMessage" class="form__error">
      {{ errorMessage }}
    </div>
    <button
      class="form__button"
      type="button"
      :disabled="isLoggingIn"
      @click="handleSubmit"
    >
      {{ isLoggingIn ? '登录中...' : '登录' }}
    </button>
  </div>
</template>

<style scoped>
/* 清除默认样式 */
*, *::before, *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

/* 设置容器最小宽度为 320px */
body {
  min-width: 320px;
}

/* 设置字体 */
body {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif,
    "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
  font-size: 16px;
}

/* 设置颜色 */
body {
  color: #333;
  background-color: #f9f9f9;
}

/* 设置表单样式 */
.form {
  margin: 1rem;
  padding: 1rem;
  background-color: #fff;
  border-radius: 0.25rem;
  box-shadow: 0 0 0.25rem rgba(0, 0, 0, 0.2);
}

.form__title {
  font-size: 1.5rem;
  margin: 0 0 1rem;
}

.form__group {
  margin-bottom: 1rem;
}

.form__label {
  display: block;
  margin-bottom: 0.25rem;
  font-size: 1rem;
}

.form__input {
  display: block;
  width: 100%;
  padding: 0.5rem;
  font-size: 1rem;
  border: 1px solid #ccc;
  border-radius: 0.25rem;
  background-color: #fff;
  transition: border-color 0.2s ease-in-out;
}

.form__input:focus {
  outline: none;
  border-color: #007bff;
}

.form__group--inline {
  display: flex;
  align-items: center;
}

.form__group--2col {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-column-gap: 1rem;
}

.form__button {
  display: block;
  width: 100%;
  padding: 0.5rem;
  font-size: 1rem;
  font-weight: 600;
  text-align: center;
  color: #fff;
  background-color: #007bff;
  border: none;
  border-radius: 0.25rem;
  transition: background-color 0.2s ease-in-out;
  cursor: pointer;
}

.form__button:focus,
.form__button:active,
.form__button:hover {
  outline: none;
  background-color: #0069d9;
}

.form__button:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.form__button--inline {
  margin-left: 0.5rem;
}

.form__error {
  margin-top: 0.5rem;
  font-size: 0.875rem;
  color: #dc3545;
}
</style>

标签:__,const,登录,form,color,适配,rem,value,vue3
From: https://www.cnblogs.com/aishangyipiyema/p/17283786.html

相关文章

  • 设置不登录访问后端
    取消多租户定义的SpringSecurity配置适配器实现/***配置URL的安全配置*<p>*anyRequest|匹配所有请求路径*access|SpringEl表达式结果为true时可以访问*anonymous|匿名可以访问*den......
  • 设置不登录访问后端
    取消多租户定义的SpringSecurity配置适配器实现@AutoConfiguration@EnableGlobalMethodSecurity(prePostEnabled=true,securedEnabled=true)publicclassYudaoWebSecurityConfigurerAdapter{@BeanprotectedSecurityFilterChainfilterChain(HttpSecurity......
  • Flask 和pythonweb框架介绍、flask快速使用、登录,显示用户信息小案例、配置文件方式、
    Flask和pythonweb框架介绍、flask快速使用、登录,显示用户信息小案例、配置文件方式、路由系统Flask和pythonweb框架介绍Flask和pythonweb框架的区别:Django框架: 大而全,内置的app很多,第三方的app很多Flask框架: 小而精,没有过多的内置app,只能完成web框架的基本功能,很多功能......
  • Vue3 v-drag 拖拽指令的简单使用
    文档官网文档:https://www.npmjs.com/package/v-drag使用安装、引入npminstallv-drag--saveimportdragfrom"v-drag"使用直接使用:<divv-drag>Dragme!</div>注意:对原本绝对定位水平居中的div,其居中的实现方式应为:div{ position:absolute; left:50%; trans......
  • 1 Flask 和pythonweb框架介绍、2 flask快速使用 、3 登录,显示用户信息小案例、4 配置
    目录1Flask和pythonweb框架介绍1.1flask介绍2flask快速使用3登录,显示用户信息小案例3.1login.html3.2home.html3.3detail.html3.4py文件4配置文件方式5路由系统5.1路由本质5.2路由参数add_url_rule5.3转换器1Flask和pythonweb框架介绍#pythonweb框架,本质都一......
  • Flask 和pythonweb框架介绍、flask快速使用、登录,显示用户信息小案例、配置文件方式、
    目录1Flask和pythonweb框架介绍1.1flask介绍2flask快速使用3登录,显示用户信息小案例3.1login.html3.2home.html3.3detail.html3.4py文件4配置文件方式5路由系统5.1路由本质5.2路由参数add_url_rule5.3转换器1Flask和pythonweb框架介绍#pythonweb框架,本质都一......
  • Vue3 watch 监听函数
    1、watch函数(既要指明监视的属性,也要指明监视的回调)坑:1)监视reactive定义的响应式数据时:oldValue无法正确获取、强制开启了深度监视(deep配置失效)2)监视reactive定义的响应式数据中某个属性时:deep配置有效setup(){letsum=ref(0)letmsg=ref('ABCD')letp......
  • vue3路由跳转params传参接收不到
      这样路由可以跳转过去,但接收到了params是一个空对象。 解决方法由于之前的params传参在页面刷新之后,参数会丢失,所以vue将这种方法移除了。vue推荐的路由跳转传参方法:1.使用query传递参数2.使用vuex、pinia对参数进行存储3.使用HistoryAPI方式传递和接收  ......
  • vue3 ant-Design-vue提交按钮放在表单外提交,自定义提交按钮
    <template><a-formref="urlEditRef":model="urlEditInfo"name="urlEdit_rule"layout="vertical"><a-form-itemlabel="跳转链接"name="longUrl":rules=&qu......
  • Vue3中修改父组件传递到子组件中的值
    Vue3中修改父组件传递到子组件中的值1.大家都知道,vue是具有单向数据流的传递特性。当你在子组件中修改父组件传递过来的数据的时候,控制台就会报出错误,说不让你对父组件传递的值进行修改。2.那么,尤大大为了解决这个问题,在vue3的时候给我们提供了一个新的思路:v-model来实现父传子,并......