企业级 Vue3 实现登录

所用的技术

  • vue3
  • element-plus
  • axios
  • pinia
  • Eslint

准备工作 

创建vue3项目

可以参考选择以下这几项

运行vue3项目

看到以下这个界面表示vue3项目创建成功

删除初始化的默认文件

删除以下文件

配置pinia

下列配置的优点

由 stores 统一维护,在 stores/index.js 中完成 pinia 初始化,交付 main.js 使用

由 stores/index.js 统一导出,导入路径统一 ./stores,而且仓库维护在 stores/modules 中

添加src/stores/modules/user.js

import { defineStore } from 'pinia'
import { ref } from 'vue'

// 用户模块
export const useUserStore = defineStore(
  'gs-user',
  () => {
    const token = ref('') // 定义 token
    const setToken = (newToken) => (token.value = newToken) // 设置 token

    return { token, setToken }
  },
  {
    persist: true // 持久化
  }
)

修改src/stores/index.js

// 从'pinia'库中引入创建Pinia实例的函数
import { createPinia } from 'pinia'
// 从'pinia-plugin-persistedstate'库中导入持久化插件
// import persist from 'pinia-plugin-persistedstate'

// 创建一个Pinia实例,用于状态管理
const pinia = createPinia()
// 使用持久化插件,使状态持久化
// pinia.use(persist)

// 导出Pinia实例,供其他模块使用
export default pinia

// 导出user模块中的所有内容,集成用户状态管理模块
export * from './modules/user.js'

修改一些文件

App.vue

<script setup></script>

<template>
  <router-view></router-view>
</template>

<style scoped></style>

router/index.js

createRouter 创建路由实例,===> new VueRouter()

路由的两种模式

1. history模式: createWebHistory()   http://xxx/user

 2. hash模式: createWebHashHistory()  http://xxx/#/user (在前缀加了’#‘)

一般使用history模式

import { createRouter, createWebHistory } from 'vue-router'

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: []
})

export default router

src/main.js

import { createApp } from 'vue'
import pinia from '@/stores/index'

import App from './App.vue'
import router from './router'

const app = createApp(App)

app.use(router)
app.use(pinia)

app.mount('#app')

新增目录api、utils

api:组织和封装与后端服务器进行交互的API接口

utils:用于存放和管理项目中可能频繁使用的工具函数或方法

引入element-plus

安装

可以选择以下方式

  • npm install element-plus --save
  • yarn add element-plus
  • pnpm install element-plus

导入 

完整导入

如果你对打包后的文件大小不是很在乎,那么使用完整导入会更方便。

import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'

app.use(ElementPlus)

自动导入(推荐)

需要安装unplugin-vue-components 和 unplugin-auto-import 这两款插件

npm install -D unplugin-vue-components unplugin-auto-import

然后把下列代码插入到 vite.config.js 配置文件中

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

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

import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue(),
    AutoImport({
      resolvers: [ElementPlusResolver()]
    }),
    Components({
      resolvers: [ElementPlusResolver()]
    })
  ],
  base: '/gs',
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url))
    }
  }
})

axios配置

安装

可以选择以下几种方式

  • npm install axios
  • yarn add axios

添加src/utils/request.js 

import { useUserStore } from '@/stores'
import axios from 'axios'
import router from '@/router'
import { ElMessage } from 'element-plus'

// 设置后端地址
const baseURL = 'http://localhost:8090'

/**
 * @description 创建axios实例
 */
const instance = axios.create({
  baseURL,
  timeout: 60000 // 设置响应时间:1min
})

/**
 * @description 请求拦截器
 */
instance.interceptors.request.use(
  (config) => {
    const userStore = useUserStore()
    // 添加token到http请求头的Authorization
    if (userStore.token) {
      config.headers.Authorization = userStore.token
    }
    return config
  },
  (err) => Promise.reject(err)
)

/**
 * @description 响应拦截器
 */
instance.interceptors.response.use(
  (res) => {
    // 响应成功
    if (res.data.code === 1) {
      return res
    }
    ElMessage({ message: res.data.msg || '服务异常', type: 'error' })
    return Promise.reject(res.data)
  },
  // 失败
  (err) => {
    ElMessage({
      message: err.response.data.msg || '服务异常',
      type: 'error'
    })
    console.log(err)
    // 如果用户未登录,状态码为 401
    if (err.response?.status === 401) {
      router.push('/login')
    }
    return Promise.reject(err)
  }
)

export default instance
export { baseURL }

配置路由

import { createRouter, createWebHistory } from 'vue-router'

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [
    // 登录页
    { path: '/login', component: () => import('@/views/login/LoginPage.vue') },
    // 布局页
    { path: '/', component: () => import('@/views/Hello/HelloPage.vue') }
  ]
})

export default router

封装后端登录api接口

添加 src/api/user.js

import request from '@/utils/request'

export const loginService = ({ username, password }) => {
  return request.post('/user/login', { username, password })
}

添加页面

 添加src/views/Hello/HelloPage.vue

<template>
  <h1>欢迎,登录成功</h1>
</template>

添加src/views/login/LoginPage.vue

<script setup>
import { ref } from 'vue'
import { loginService } from '@/api/user'
import { useUserStore } from '@/stores'
import { useRouter } from 'vue-router'
const form = ref()
const router = useRouter()
const userStore = useUserStore()

const loginModel = ref({
  username: '',
  password: ''
})

// 非空校验
const rules = {
  username: [{ required: true, message: '账号不能为空', trigger: 'blur' }],
  password: [{ required: true, message: '密码不能为空', trigger: 'blur' }]
}

const login = async () => {
  await form.value.validate()
  const res = await loginService(loginModel.value)
  console.log(res)
  userStore.setToken(res.data.token)
  ElMessage.success('登录成功')
  router.push('/')
}
</script>

<template>
  <div class="container">
    <div class="login-wrapper">
      <div class="header">登录</div>
      <el-form
        class="form-wrapper"
        :model="loginModel"
        :rules="rules"
        ref="form"
      >
        <el-form-item label="账号:" prop="username">
          <el-input
            placeholder="请输入账号"
            v-model="loginModel.username"
          ></el-input>
        </el-form-item>
        <el-form-item label="密码:" class="password" prop="password">
          <el-input
            placeholder="请输入密码"
            type="password"
            v-model="loginModel.password"
          ></el-input>
        </el-form-item>
        <el-form-item>
          <el-button class="btn" @click="login">登录</el-button>
        </el-form-item>
      </el-form>
    </div>
  </div>
</template>

<style>
.container {
  background-image: linear-gradient(to right, #fbc2eb, #a6c1ee);
  width: 100%;
  height: 100vh;
}

.login-wrapper {
  background-color: #fff;
  width: 358px;
  height: 588px;
  border-radius: 15px;
  padding: 0 50px;
  position: relative;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
}

.header {
  font-size: 38px;
  font-weight: bold;
  text-align: center;
  line-height: 200px;
}

.password {
  margin-top: 30px;
}

.btn {
  color: #fff;
  font-size: large;
  margin-top: 40px;
  height: 45px;
  width: 100%;
  background-image: linear-gradient(to right, #a6c1ee, #fbc2eb);
}
</style>

运行代码

npm run dev

打开http://localhost:5173/gs/login,看到以下图片页面部署成功

记得启动后端哦

账号密码正确:

密码错误:

账号错误:

  • 10
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值