效果
准备
背景图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/i18nimport 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-globalpropertiesapp.config.globalProperties.$message = ElMessageapp.config.globalProperties.$notify = ElNotificationapp.config.globalProperties.$confirm = ElMessageBox.confirmapp.config.globalProperties.$alert = ElMessageBox.alertapp.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%B0path: '/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-formclass="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-inputplaceholder="请输入用户名"/></el-form-item><el-form-item><span class="svg-container"><svg-icon icon-class="password"></svg-icon></span><el-inputplaceholder="请输入密码"autocomplete="on"/></el-form-item><!-- 登录按钮 --><el-buttontype="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
