代码改变世界

vue3+element-plus表单验证之登录

2021-07-12 14:14  镌刻成诗  阅读(2082)  评论(0)    收藏  举报

vue3+element-plus表单验证之登录

上代码

<template>
  <div class="container">
    <div class="sign-in">
      <!-- 登录 -->
      <el-form
        class="form login-form clear-fix"
        ref="loginFormRef"
        :model="loginForm"
        :rules="loginRules"
      >
        <el-form-item label="邮箱" prop="email">
          <el-input v-model="loginForm.email" type="text" placeholder="请输入邮箱地址" ></el-input>
        </el-form-item>
        <el-form-item label="密码" prop="pass">
          <el-input v-model="loginForm.pass" type="password" placeholder="请输入密码"></el-input>
        </el-form-item>
        <el-form-item>
          <el-row gutter="10px">
            <el-col :span="12">
              <el-button
                type="primary"
                class="form-btn submit-btn"
                @click="submitForm"
                v-if="!successMode"
                >
                提交
              </el-button>
              <el-button
                type="success"
                v-else
                class="form-btn"
                >
                登录成功
              </el-button>
            </el-col>
            <el-col :span="12">
              <el-button
                class="form-btn reset-btn"
                @click="resetForm()"
                >
                重置
              </el-button>
            </el-col>
          </el-row>
        </el-form-item>
        <!-- 找回密码 -->
        <div class="tiparea">
          <p>
            忘记密码?
            <el-link type="primary">找回密码</el-link>
          </p>
        </div>
      </el-form>
    </div>
    <div class="sign-up"></div>
  </div>
</template>

<script lang="ts">
import { ref, defineComponent, reactive, unref } from 'vue'
import { useRouter } from 'vue-router'

// 对密码和邮箱进行类型限制
interface loginData {
  email: string;
  pass: string;
}

export default defineComponent({
  setup () {
    const loginForm = ref<loginData>({
      email: '',
      pass: ''
    })
    const router = useRouter()
    const loginFormRef = ref()
    // 自定义验证规则
    const validatePass = (rule, value, callback) => {
      //  密码只能由大小写英文字母或数字开头,且由大小写英文字母_.组成
      const reg = /^[A-Za-z0-9][A-Za-z0-9_.]{5,14}$/
      console.log('reg', value.match(reg))
      if (!value.match(reg)) {
        callback(new Error('密码由字母或数字开头,且只能为字母,数字,下划线及(.)'))
      } else {
        callback()
      }
    }
    // 定义校验规则
    const loginRules = reactive({
      email: [
        { required: true, message: '邮箱不能为空', trigger: 'blur' },
        { type: 'email', message: '邮箱格式不正确', trigger: 'blur' }
      ],
      pass: [
        { required: true, message: '密码不能为空', trigger: 'blur' },
        { min: 6, max: 15, message: '密码位数只能在6~15之间', trigger: 'blur' },
        { validator: validatePass, trigger: 'blur' }
      ]
    })
    // 是否登录成功
    const successMode = ref<boolean>(false)
    // 重置表单
    const resetForm = () => {
      // 笨办法这么写:
      // loginForm.value.email = ''
      // loginForm.value.pass = ''
      // 明眼人这么写:
      const form = unref(loginFormRef)
      form.resetFields()
    }
    // 路由跳转
    function goto () {
      router.push('/')
    }
    // 表单提交
    const submitForm = async () => {
      const form = unref(loginFormRef)
      if (!form) {
        return
      }
      try {
        await form.validate()
        successMode.value = true
        // 路由跳转
        goto()
      } catch (err) {
        console.log(err)
      }
    }
    return {
      loginFormRef,
      loginForm,
      loginRules,
      resetForm,
      submitForm,
      successMode,
      goto
    }
  }
})
</script>

<style lang="scss" scoped>
.container {
  width: 100%;
  height: 100%;
  overflow: hidden;
}
.form {
  width: 360px;
  padding: 20px;
  border-radius: 10px;
}

.tiparea {
  float: right;
  a {
    color: blue;
    &:hover {
      color: red;
      cursor: pointer;
    }
  }
}

.form {
  border: 1px solid #ddd;
}

.clear-fix::after {
  display: table;
  content: "";
  overflow: hidden;
  clear: both;
}

.login-form {
  box-shadow: 5px 5px 5px 5px darken(#145885, 0.1);
}
.form-btn {
  width: 48%;
}
.reset-btn {
  float: right;
}
.sign-in {
  background: url('../assets/login.jpg') no-repeat;
  background-size: cover;
  width: 100%;
  height: 100%;
  position: relative;
}
.el-form {
  position: absolute;
  right: 200px;
  top: 200px;
  background-color: #fff;
}
</style>

描述

诸君皆明白,setup是拿不到this的。但是官网的案例中是由用到this的,官网没在setup中写。

比如:自定义表单验证官网是这样的:

var validatePass = (rule, value, callback) => {
        if (value === '') {
          callback(new Error('请输入密码'));
        } else {
          if (this.ruleForm.checkPass !== '') {
            this.$refs.ruleForm.validateField('checkPass');
          }
          callback();
        }
      }

再比如表单提交和重置官网再methods里面这样写的

methods: {
      submitForm(formName) {
        this.$refs[formName].validate((valid) => {
          if (valid) {
            alert('submit!');
          } else {
            console.log('error submit!!');
            return false;
          }
        });
      },
      resetForm(formName) {
        this.$refs[formName].resetFields();
      }
    }
  }

他们都用到了this.refs

那么setup中没有this怎么实现呢?

有人如下面这般做的,用这种方式获取组件的实例,但是也有人认为setup中取消this获取实例就是要杜绝使用者获取实例,原因是在某些情况下,编码会变得很复杂,但是有人偏偏这么干,究竟该提倡了还是该反对?我觉得既然vue这么设计,那么使用者应该尽量遵循某些设计理念。

import {getCurrentInstance} from 'vue'
const instance = getCurrentInstance()
看看form中的属性

如同官网一样,我这里也给了form三个必要的属性

<el-form
        class="form login-form clear-fix"
        ref="loginFormRef"
        :model="loginForm"
        :rules="loginRules"
      >
            ...
</el-form>

只不过官网的ref是通过this来获取表单元素的的,在setup中我们可以换种方式获取,比如:

在setup中创建一个ref对象

const loginFormRef = ref()

在return中返回

return { loginFormRef }

如何使用:比如重置表单数据

// 重置表单
    const resetForm = () => {
      // 笨办法这么写:
      // loginForm.value.email = ''
      // loginForm.value.pass = ''
      // 明眼人这么写:
      const form = unref(loginFormRef)
      form.resetFields()
    }

官网是这么做的:

当然这里的formName传的是'loginFormRef'

resetForm(formName) {
   this.$refs[formName].resetFields();
}
那么我们如何用正确的姿势优雅地进行表单提交呢?
// 表单提交
    const submitForm = async () => {
      const form = unref(loginFormRef)
      if (!form) {
        return
      }
      try {
        await form.validate()
        successMode.value = true
        // 路由跳转
        goto()
      } catch (err) {
        console.log(err)
      }
    }
表单提交后如何路由跳转?

首先要引入:

import { useRouter } from 'vue-router'

人后在setup下

const router = useRouter()

然后要在setup中定义一个路由跳转的函数

// 路由跳转
    const goto = () => {
      router.push('/')
    }

你还需要在setup的return中返回这个函数

return { goto }
  • 而且貌似只能这么做,只能在setup下,不能再setup下的方法中
  • 比如在提交的方法中才定义const router = useRouter()
  • 我试过行不通哈
大功告成,当然只是简短的做通了一个流程,希望你运气好,别像我一样把:model属性写成了:mode结果搞得差点怀疑人生