效果
准备
背景图svg
准备body.svg
注册相关element组件
src/plugins/element.ts
import { App } from 'vue'
import {
locale,
ElButton,
ElMessage,
ElNotification,
ElMessageBox,
ElMenu,
ElMenuItem,
ElSubmenu,
ElRow,
ElCol,
ElBreadcrumb,
ElBreadcrumbItem,
ElTooltip,
ElDropdown,
ElDropdownMenu,
ElDropdownItem,
ElScrollbar,
ElDrawer,
ElColorPicker,
ElSwitch,
ElForm,
ElFormItem,
ElInput
} from 'element-plus'
// 默认主题
// import 'element-plus/lib/theme-chalk/index.css'
// Element Plus 组件内部默认使用英语
// https://element-plus.gitee.io/#/zh-CN/component/i18n
import lang from 'element-plus/lib/locale/lang/zh-cn'
// Element Plus 直接使用了 Day.js 项目的时间日期国际化设置, 并且会自动全局设置已经导入的 Day.js 国际化配置。
import 'dayjs/locale/zh-cn'
// $ELEMENT size属性类型
export type Size = 'default' | 'medium' | 'small' | 'mini'
interface ElementOptions {
size: Size
}
export default (app: App, options: ElementOptions): void => {
locale(lang)
// 按需导入组件列表
const components = [
ElButton,
ElMessage,
ElNotification,
ElMessageBox,
ElMenu,
ElMenuItem,
ElSubmenu,
ElRow,
ElCol,
ElBreadcrumb,
ElBreadcrumbItem,
ElTooltip,
ElDropdown,
ElDropdownMenu,
ElDropdownItem,
ElScrollbar,
ElDrawer,
ElColorPicker,
ElSwitch,
ElForm,
ElFormItem,
ElInput
]
components.forEach(component => {
app.component(component.name, component)
})
// Vue.prototype 替换为 config.globalProperties
// 文档说明 https://v3.cn.vuejs.org/guide/migration/global-api.html#vue-prototype-%E6%9B%BF%E6%8D%A2%E4%B8%BA-config-globalproperties
app.config.globalProperties.$message = ElMessage
app.config.globalProperties.$notify = ElNotification
app.config.globalProperties.$confirm = ElMessageBox.confirm
app.config.globalProperties.$alert = ElMessageBox.alert
app.config.globalProperties.$prompt = ElMessageBox.prompt
// 全局配置 https://element-plus.gitee.io/#/zh-CN/component/quickstart#quan-ju-pei-zhi
// 该对象目前支持 size 与 zIndex 字段。size 用于改变组件的默认尺寸 small,zIndex 设置弹框的初始 z-index(默认值:2000)。
app.config.globalProperties.$ELEMENT = {
size: options.size
}
}
注册登录路由
src/router/index.ts
注册login路由 放到constantRoutes集合里
import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router'
import Layout from '@/layout/index.vue'
// 看作是异步获取路由
export const asyncRoutes: Array<RouteRecordRaw> = [
{
path: '/documentation',
component: Layout, // 布局组件作为一级路由
redirect: '/documentation/index',
children: [
{
path: 'index',
name: 'Documentation',
component: () => import(/* webpackChunkName: "documentation" */ '@/views/documentation/index.vue'),
meta: {
title: 'Documentation',
icon: 'documentation',
hidden: false, // 菜单栏不显示
// 路由是否缓存 没有这个属性或false都会缓存 true不缓存
noCache: false
}
}
]
},
{
path: '/guide',
component: Layout,
redirect: '/guide/index',
children: [
{
path: 'index',
name: 'Guide',
component: () => import(/* webpackChunkName: "guide" */ '@/views/guide/index.vue'),
meta: {
title: 'Guide',
icon: 'guide'
// 当guide路由激活时高亮选中的是 documentation/index菜单
// activeMenu: '/documentation/index'
}
}
]
},
{
path: '/system',
component: Layout,
redirect: '/system/user',
meta: {
title: 'System',
icon: 'lock',
alwaysShow: true // 根路由始终显示 哪怕只有一个子路由
},
children: [
{
path: 'menu',
name: 'Menu Management',
component: () => import(/* webpackChunkName: "menu" */ '@/views/system/menu.vue'),
meta: {
title: 'Menu Management',
hidden: false,
breadcrumb: false
}
},
{
path: 'role',
name: 'Role Management',
component: () => import(/* webpackChunkName: "role" */ '@/views/system/role.vue'),
meta: {
title: 'Role Management',
hidden: false
}
},
{
path: 'user',
name: 'User Management',
component: () => import(/* webpackChunkName: "user" */ '@/views/system/user.vue'),
meta: {
title: 'User Management'
}
}
]
},
{ // 外链路由
path: '/external-link',
component: Layout,
children: [
{
path: 'https://www.baidu.com/',
redirect: '/',
meta: {
title: 'External Link',
icon: 'link'
}
}
]
},
{ // 404一定放在要在最后面
path: '/:pathMatch(.*)*',
redirect: '/404',
meta: {
hidden: true
}
}
]
export const constantRoutes: Array<RouteRecordRaw> = [
{
path: '/',
component: Layout,
redirect: '/dashboard',
children: [
{
path: 'dashboard',
name: 'Dashboard',
component: () => import(/* webpackChunkName: "dashboard" */ '@/views/dashboard/index.vue'),
meta: {
title: 'Dashboard',
// icon: 'dashboard'
icon: 'el-icon-platform-eleme',
affix: true // 固定显示在tagsView中
}
}
]
},
{
path: '/redirect',
component: Layout,
meta: {
hidden: true
},
children: [
{ // 带参数的动态路由正则匹配
// https://next.router.vuejs.org/zh/guide/essentials/route-matching-syntax.html#%E5%8F%AF%E9%87%8D%E5%A4%8D%E7%9A%84%E5%8F%82%E6%95%B0
path: '/redirect/:path(.*)', // 要匹配多级路由 应该加*号
component: () => import('@/views/redirect/index.vue')
}
]
},
{
path: '/login',
name: 'Login',
component: () => import('@/views/login/index.vue')
},
{
path: '/401',
component: Layout,
children: [
{
path: '',
component: () => import('@/views/error-page/401.vue'),
meta: {
title: '401',
icon: '404',
hidden: true
}
}
]
},
{
path: '/404',
component: () => import('@/views/error-page/404.vue'),
meta: {
hidden: true // 404 hidden掉
}
}
]
export const routes = [
...constantRoutes,
...asyncRoutes
]
const router = createRouter({
history: createWebHashHistory(),
routes
})
export default router
创建login路由
src/views/login/index.vue
<template>
<div class="login-container">
<el-form
class="login-form"
>
<div class="admin-logo">
<img class="logo" src="../../assets/logo.png" alt="logo">
<h1 class="name">Vue3 Admin</h1>
</div>
<el-form-item prop="username">
<span class="svg-container">
<svg-icon icon-class="user"></svg-icon>
</span>
<el-input
placeholder="请输入用户名"
/>
</el-form-item>
<el-form-item>
<span class="svg-container">
<svg-icon icon-class="password"></svg-icon>
</span>
<el-input
placeholder="请输入密码"
autocomplete="on"
/>
</el-form-item>
<!-- 登录按钮 -->
<el-button
type="primary"
style=" width: 100%; margin-bottom: 30px"
:loading="loading"
@click="handleLogin"
>Login</el-button>
</el-form>
</div>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue'
export default defineComponent({
name: 'Login',
setup() {
const loading = ref(false)
const handleLogin = () => {
console.log('login')
}
return {
loading,
handleLogin
}
}
})
</script>
<style lang="scss">
$bg:#283443;
$light_gray:#fff;
$cursor: #fff;
.login-container {
.el-form-item {
border: 1px solid #dcdee2;
border-radius: 5px;
padding-left: 10px;
.el-input {
display: inline-block;
height: 40px;
width: 85%;
input {
background: transparent;
border: 0;
-webkit-appearance: none;
border-radius: 0px;
padding: 12px 5px 12px 15px;
height: 40px;
}
}
}
}
</style>
<style lang="scss" scoped>
$bg:#2d3a4b;
$dark_gray:#889aa4;
$light_gray:#eee;
.login-container {
min-height: 100%;
width: 100%;
overflow: hidden;
background-image: url('../../assets/body.svg');
background-repeat: no-repeat;
background-position: 50%;
background-size: 100%;
.login-form {
position: relative;
width: 500px;
max-width: 100%;
margin: 0 auto;
padding: 140px 35px 0;
overflow: hidden;
box-sizing: border-box;
.admin-logo {
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 20px;
.logo {
width: 60px;
height: 60px;
}
.name {
font-weight: normal;
margin-left: 10px;
}
}
}
}
</style>
本节参考源码
https://gitee.com/brolly/vue3-element-admin/commit/b923a1ad3a37371bd9b99e1838e2e96346857186