Vue3+node.js实现登录

发布于:2024-11-29 ⋅ 阅读:(14) ⋅ 点赞:(0)

前端代码实现

效果图
在这里插入图片描述
前端代码实现

<template>
    <div class="login-container">
        <el-card class="login-card">
            <template #header>
                <div class="card-header">
                    <span>登录</span>
                </div>
            </template>
            <el-form label-width="80px" ref="formRef" :model="formData" :rules="rules">
                <el-form-item label="用户名" prop="username">
                    <el-input v-model="formData.username" placeholder="请输入用户名" ></el-input>
                </el-form-item>
                <el-form-item label="密码"  prop="password">
                    <el-input v-model="formData.password" type="password" placeholder="请输入密码"></el-input>
                </el-form-item>
                <el-form-item>
                    <el-button style="width: 100%;"  @click="handleSubmit"  type="primary">登录</el-button>
                </el-form-item>
                <el-form-item >
                    <el-button link type="info" @click="toggleToLogin"  >没有账号?去注册</el-button>
                </el-form-item>
            </el-form>
        </el-card>
    </div>
  </template>
  
  
  <script setup>
  import { ElMessage } from 'element-plus';
  import axios from 'axios';
  import { reactive, ref } from 'vue';
  
  //初始化
  const formRef = ref(null)
  //跳转注册页面
  const toggleToLogin = () => {
  location.href = '/register'
  }
  //表单数据
  const formData = ref({
    username:'',
    password:''
  }) 
// 修正校验规则
const rules = reactive({
    username:[
        {required: true, message: '请输入用户名', trigger: 'blur'},
        {min: 3, max: 20, message: '长度3到20个字符', trigger: 'blur'} 
    ],
    password:[
        {required: true, message: '请输入密码', trigger: 'blur'},
        {min: 3, max: 20, message: '长度在3到20个字符', trigger: 'blur'}
    ]
})

// 登录处理
const handleSubmit = async () => {
    const form = formRef.value
    if(!form) return;
    try {
      await form.validate();
      const res = await axios.post('http://localhost:3030/user/login', formData.value);
      
      if(res.data.code === 200) {  
        ElMessage.success( '登录成功');
        
        location.href = '/manager/home';
      } else {
        ElMessage.error( '登录失败');
      }
    } catch (error) {
      console.error('登录请求错误', error);
      ElMessage.error(error.response?.data?.message || '登录失败,请稍后重试');
    }
}
  </script>
  
  
  <style scoped>
  .login-container {
    min-height: 100vh;
    display: flex;
    background-color: aqua;
    align-items: center;
    justify-content: center;
  }
  .login-card {
    width: 400px;
    border-radius: 8px;
  }
  .card-header {
    font-size: 24px;
    font-weight: bold;
    text-align: center;
  }
  
  </style>

后端代码实现

创建文件夹router,在router目录下创建path.js文件

//登录
router.post('/login', async (req,res)=>{
    try {
        const {username, password} = req.body
        
        // 验证参数
        if(!username?.trim() || !password?.trim()){  // 增加trim()检查
            return res.status(400).json({
                code: 400,
                message: '用户名和密码不能为空'
            })
        }

        const sql = 'select * from user where username = ? limit 1'
        const [rows] = await pool.query(sql,[username])
        
        if(rows.length === 0){
            return res.status(401).json({
                code: 401,
                message: '用户名或密码错误'  
            })
        }

        const user = rows[0]
        if(user.password !== password){
            return res.status(401).json({
                code: 401,
                message: '用户名或密码错误'
            })
        } 

        // 删除敏感信息
        delete user.password
        
        success(res, {
            code: 200,
            user,
            message: '登录成功'
        })
    } catch (error) {
        handleError(res, error)
    }
})

跨域处理

前端跨域,在vite.config.js中添加跨域请求

import { fileURLToPath, URL } from 'node:url'

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueDevTools from 'vite-plugin-vue-devtools'

// https://vite.dev/config/
export default defineConfig({
  plugins: [
    vue(),
    vueDevTools(),
  ],
  server:{
    proxy:{
      '/api':{target:'http://localhost:3030',changeOrigin:true,
        rewrite:(path) => path.replace(/^\/api/,'')
      }
    }
  },
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url))
    },
  },
})

后端跨域,创建app.js,导入路由

const express = require('express')
const cors = require('cors')
const router = require('./router/path')


const app = express()

//解析数据
app.use(express.json())
app.use(express.urlencoded({extended:true}))
//跨域处理
app.use(cors(
    {
        origin:['http://localhost:5173'],
        methods:['GET','POST','PUT','DELETE'],
        credentials:true,
        allowedHeaders:['Content-Type']
    }
))

app.use('/user',router)

const PORT = process.env.PORT || 3030
app.listen(PORT,()=>{
    console.log(`服务正在运行...端口为${PORT}`)
})

实现注册界面