展开
拓展 关闭
订阅号推广码
GitHub
视频
公告栏 关闭

vite2 + vue3实现curd(三):实现登录、注册

前言

  • 实现需求
  • 表单验证
  • 防抖和节流
  • 登录预验证
  • 路由导航守卫

参考

开发步骤

  • 向后端发送post请求前需进行表单验证
<script lang="ts">
export default {
  data() {
    return {
      ruleForm: {
        name: '',
        pass: '',
      },
      flag: false,   // 默认该按钮不是禁用状态
      rules: {
        name: [
          {
            required: true,
            message: '请输入用户名!',
            trigger: 'blur',
          },
        ],
        pass: [
          {
            required: true,
            message: '请输入密码!',
            trigger: 'blur',
          },
        ],
      },
    }
  },
}
</script>

  • 对提交按钮进行防抖和节流操作:提交按钮点击一次后隔2秒才能再次点击,避免用户狂点,减轻服务器压力
<template>
    <div>
        <el-form-item>
            <!-- 提交按钮 -->
            <el-button type="primary" @click="submitForm('ruleForm')" :disabled='flag'
              >Login</el-button
            >
            <el-button @click="resetForm('ruleForm')">Reset</el-button>
        </el-form-item>
    </div>
</template>

<script lang="ts">
export default {
  data() {
    return {
      flag: false,   // 默认该按钮不是禁用状态
  methods: {
    submitForm(formName) {
      this.$refs[formName].validate((valid) => {
        if (valid) {
          console.log(this.ruleForm)
          this.flag = true;
          setTimeout(()=>{
              console.log("可再次提交!")
              this.flag= false;
          }, 2000)
        } else {
          console.log('error submit!!')
          return false
        }
      })
    },
    resetForm(formName) {
      this.$refs[formName].resetFields()
    },
  },
}
</script>

  • element plus的表单中封装了validate函数,只有通过了表单验证才能向后端发送请求
<script lang="ts">
export default {
  methods: {
    submitForm(formName) {
      this.$refs[formName].validate((valid) => {
        if (valid) {
          // 验证通过后在这里发送post请求
          alert('submit!')
        } else {
          // 验证未通过的处理
          console.log('error submit!!')
          return false
        }
      })
    },
    resetForm(formName) {
      this.$refs[formName].resetFields()
    },
  },
}
</script>

  • 自定义验证规则时,在自定义的规则中添加callback()回调函数,否则验证完后永远无法进入validate函数,这里是一个坑
<script lang="ts">
export default {
  data() {
    const checkName = (rule, value, callback) => {
      if (!value) {
        return callback(new Error('请输入用户名!'))
      } else {
        callback()
      }
    }
    const validatePass = (rule, value, callback) => {
      if (value === '') {
        callback(new Error('请输入密码!'))
      } else {
        if (this.ruleForm.checkPass !== '') {
          this.$refs.ruleForm.validateField('checkPass')
        }
        callback()
      }
    }
    const validatePass2 = (rule, value, callback) => {
      if (value === '') {
        callback(new Error('请再次输入密码!'))
      } else if (value !== this.ruleForm.pass) {
        callback(new Error("两次密码不一致!"))
      } else {
        callback()
      }
    }
    return {
      ruleForm: {
        pass: '',
        checkPass: '',
        name: '',
      },
      rules: {
        pass: [{ validator: validatePass, trigger: 'blur' }],
        checkPass: [{ validator: validatePass2, trigger: 'blur' }],
        name: [{ validator: checkName, trigger: 'blur' }],
      },
      flag: false,   // 默认该按钮不是禁用状态
    }
  },
  methods: {
    submitForm(formName) {
      this.$refs[formName].validate((valid) => {
        if (valid) {
          // 验证通过后的处理
          console.log("success submit!")
        } else {
          console.log('error submit!!')
          return false
        }
      })
    },
    resetForm(formName) {
      this.$refs[formName].resetFields()
    },
  },
}
</script>

  • 使用路由导航守卫:不能直接通过url跳转到控制台,只有当用户登录后才能访问控制台组件
<!-- 发送post请求进行登录,登录成功后将token保存到sessionStorage,同时跳转到控制台 -->
<script lang="ts">
export default {
  methods: {
    submitForm(formName) {
      this.$refs[formName].validate((valid) => {
        if (valid) {
          console.log(this.ruleForm)
          this.flag = true;
          // 登录 post请求
          const username = this.ruleForm.name;
          const password = this.ruleForm.pass;
          const reqData = {    
            username: username,    
            password,    
          } 
          this.$http.post("user/login", reqData).then((response)=>{
            console.log(response)
            // 将token保存到sessionStorage
            window.sessionStorage.setItem('token', response.data)
            // 跳转到home路由
            this.$router.push('/consoleManage')
          }).catch(error=>{console.error(error)});
          // 登录结束
          setTimeout(()=>{
              console.log("可再次提交!")
              this.flag= false;
          }, 2000)
        } else {
          console.log('error submit!!')
          return false
        }
      })
    },
    resetForm(formName) {
      this.$refs[formName].resetFields()
    },
  },
}
</script>

  • 在项目入口main.js中全局配置路由导航守卫
// router
import router from './route/index'

// 路由导航守卫
router.beforeEach((to, from, next) => {
    // 要跳转到控制台页面时,先查看本地是否存在token,没有则返回登录页面
    if(to.path === '/consoleManage') {
        const tokenStr = window.sessionStorage.getItem('token')
        if(!tokenStr) return next('/userLogin')
    }    
    next() 
})

  • 登录时表单验证效果

  • 登录成功后查看sessionStorage

  • 退出登录

<template>
    <div>
        <el-button type="info" @click="logout">退出登录</el-button>
    </div>
</template>

<script>
export default {
    methods: {
        logout() {
            window.sessionStorage.clear();  // 清除sessionStorage中的token
            this.$router.push("/login");   // 跳转到登录路由
        }
    }
};
</script>

  • 注册用户实现源码
点击查看详情
<template>
    <div class="box">
        <img src="https://pic.imgdb.cn/item/61b812a02ab3f51d91b0a6ca.png" alt="">
        <div class="register_box">
            <span class="regiter_span">注册用户</span>
            <el-form
                ref="ruleForm"
                :model="ruleForm"
                status-icon
                :rules="rules"
                label-width="120px"
                class="demo-ruleForm"
            >
                <span class="icon_avatar">
                    <el-icon><Avatar /></el-icon>
                </span>
                <el-form-item label="UserName" prop="name">
                <el-input v-model.number="ruleForm.name"></el-input>
                </el-form-item>
                <span class="icon_unlock">
                    <el-icon><Unlock /></el-icon>
                </span>
                <el-form-item label="Password" prop="pass">
                <el-input
                    v-model="ruleForm.pass"
                    type="password"
                    autocomplete="off"
                ></el-input>
                </el-form-item>
                <span class="icon_Sugar">
                    <el-icon><Sugar /></el-icon>
                </span>
                <el-form-item label="ReUsePass" prop="checkPass">
                <el-input
                    v-model="ruleForm.checkPass"
                    type="password"
                    autocomplete="off"
                ></el-input>
                </el-form-item>
                <el-form-item>
                <el-button type="primary" @click="submitForm('ruleForm')" :disabled='flag'
                    >Submit</el-button
                >
                <el-button @click="resetForm('ruleForm')" class="but_re">Reset</el-button>
                </el-form-item>
            </el-form>
            <span class="regiter_link">
                <router-link to="/"> 已有账号,去登录</router-link>
            </span>
        </div>
    </div>
</template>

<script lang="ts">
// icon
import { Avatar, Unlock, Sugar } from '@element-plus/icons'
export default {
  components: {
    Unlock,
    Avatar,
    Sugar
  },
  setup() {
    
  },
  data() {
    const checkName = (rule, value, callback) => {
      if (!value) {
        return callback(new Error('请输入用户名!'))
      } else {
        callback()
      }
    }
    const validatePass = (rule, value, callback) => {
      if (value === '') {
        callback(new Error('请输入密码!'))
      } else {
        if (this.ruleForm.checkPass !== '') {
          this.$refs.ruleForm.validateField('checkPass')
        }
        callback()
      }
    }
    const validatePass2 = (rule, value, callback) => {
      if (value === '') {
        callback(new Error('请再次输入密码!'))
      } else if (value !== this.ruleForm.pass) {
        callback(new Error("两次密码不一致!"))
      } else {
        callback()
      }
    }
    return {
      ruleForm: {
        pass: '',
        checkPass: '',
        name: '',
      },
      rules: {
        pass: [{ validator: validatePass, trigger: 'blur' }],
        checkPass: [{ validator: validatePass2, trigger: 'blur' }],
        name: [{ validator: checkName, trigger: 'blur' }],
      },
      flag: false,   // 默认该按钮不是禁用状态
    }
  },
  methods: {
    submitForm(formName) {
      this.$refs[formName].validate((valid) => {
        if (valid) {
          // console.log(this.ruleForm)
          this.flag = true;
          // 注册 post请求
          const username = this.ruleForm.name;
          const password = this.ruleForm.pass;
          const reqData = {    
            username: username,    
            password,    
          } 
          this.$http.post("user/register", reqData).then((response)=>{
            console.log(response)
            if(response.code == 200 ) {
              console.log("注册成功!")
              // 跳转到home路由
              this.$router.push('/userLogin')
            }
          }).catch(error=>{console.error(error)});
          // 注册结束
          setTimeout(()=>{
              console.log("可再次提交!")
              this.flag= false;
          }, 2000)
        } else {
          console.log('error submit!!')
          return false
        }
      })
    },
    resetForm(formName) {
      this.$refs[formName].resetFields()
    },
  },
}
</script>

<style lang="less">
.box {
    width: 100%;
    height: 100%;
}
img {
    float: left;
    height: 810px;
    width: 1556px;
    opacity: 0.7;
}
.register_box {
    width: 450px;
    height: 380px;
    border-radius: 5px;
    border: 2px gray solid;
    float: left;
    position: absolute;
    top: 200px;
    left: 500px;
    background-color: white;
    opacity: 0.7;
}
.regiter_span {
    font-size: larger;
    position: relative;
    top: 15px;
    left: 180px;
}
.el-form {
    position: relative;
    top: 15px;
    padding-right: 20px;
}
.icon_avatar{
    position: relative;
    top: 30px;
    left: 20px;
}
.icon_unlock{
    position: relative;
    top: 30px;
    left: 20px;
}
.icon_Sugar {
    position: relative;
    top: 30px;
    left: 20px;
}
.regiter_link {
    position: relative;
    left: 305px;
    top: 13px;
}
.el-button {
    position: relative;
    top: 35px;
    left: 150px;
}
.el-button {
    position: relative;
    top: 5px;
    left: 20px;
}
.but_re{
    position: relative;
    left: 70px;
}
</style>

  • 表单验证效果

补充

  • 发送post请求时报错:415Unsupported media type
  • 错误原因:传给后端接口的参数格式不正确
  • 解决错误:这是因为我自己封装的axios有问题,注释掉如下代码即可
posted @ 2021-12-14 13:46  DogLeftover  阅读(159)  评论(0编辑  收藏  举报