Vue3-Element-Admin 登录页布局切换器
📅 2026/7/28 2:14:04
👁️ 阅读次数
📝 编程学习
Vue3-Element-Admin 登录页布局切换器(Login Layout Switcher)
概述
登录页支持三种布局模式切换:居左(left)、居中(center)、居右(right),用户选择后自动持久化到localStorage,刷新页面保持上次选择。
灵感来源:Vben5 Admin 登录页
涉及文件
| 文件 | 类型 | 说明 |
|---|---|---|
src/views/login/components/AuthLayoutSwitch.vue | 新增 | 布局切换下拉组件 |
src/views/login/index.vue | 修改 | 登录页主视图,集成布局切换 |
架构设计
┌─────────────────────────────────────────────────┐ │ login/index.vue │ │ │ │ authLayout = useStorage("auth-layout", "right")│ │ │ │ │ ▼ │ │ ┌──────────────────┐ │ │ │ AuthLayoutSwitch │◄── v-model="authLayout" │ │ │ (Dropdown 组件) │ │ │ └──────────────────┘ │ │ │ │ │ ▼ │ │ :class="`auth-view--${authLayout}`" │ │ │ │ │ ├── .auth-view--left → 表单居左 │ │ ├── .auth-view--center → 表单居中 │ │ └── .auth-view--right → 表单居右(默认) │ └─────────────────────────────────────────────────┘组件详解
AuthLayoutSwitch.vue
布局切换下拉组件,基于 Element Plusel-dropdown实现。
核心设计:
- 使用
defineModel<AuthLayout>()实现双向绑定 - 导出
AuthLayout类型供父组件使用 - 三种布局对应三个
@element-plus/icons-vue图标:Postcard→ 居左Tickets→ 居中CreditCard→ 居右
<template> <el-dropdown trigger="click" @command="handleCommand"> <el-icon :size="20"> <component :is="layoutIcons[modelValue]" /> </el-icon> <template #dropdown> <el-dropdown-menu> <el-dropdown-item v-for="item in layoutOptions" :key="item.value" :command="item.value" :disabled="modelValue === item.value" > <el-icon> <component :is="item.icon" /> </el-icon> {{ item.label }} </el-dropdown-item> </el-dropdown-menu> </template> </el-dropdown> </template> <script setup lang="ts"> import { Postcard, Tickets, CreditCard } from "@element-plus/icons-vue"; export type AuthLayout = "left" | "center" | "right"; const modelValue = defineModel<AuthLayout>({ default: "right" }); const layoutIcons: Record<AuthLayout, typeof Postcard> = { left: Postcard, center: Tickets, right: CreditCard, }; const layoutOptions = [ { label: "居左", value: "left" as AuthLayout, icon: Postcard }, { label: "居中", value: "center" as AuthLayout, icon: Tickets }, { label: "居右", value: "right" as AuthLayout, icon: CreditCard }, ]; function handleCommand(val: AuthLayout) { modelValue.value = val; } </script>login/index.vue 集成
Template 关键改动:
<!-- 根元素动态 class --> <div class="auth-view" :class="`auth-view--${authLayout}`"> <!-- 工具栏中加入布局切换 --> <el-tooltip content="视图布局" placement="bottom"> <div class="toolbar-item"> <AuthLayoutSwitch v-model="authLayout" /> </div> </el-tooltip> <!-- 居中模式隐藏产品介绍区域 --> <section v-if="authLayout !== 'center'" class="auth-feature"> ... </section>Script 关键改动:
import{useStorage}from"@vueuse/core";importAuthLayoutSwitchfrom"./components/AuthLayoutSwitch.vue";importtype{AuthLayout}from"./components/AuthLayoutSwitch.vue";// localStorage 持久化,key: "auth-layout",默认值: "right"constauthLayout=useStorage<AuthLayout>("auth-layout","right");三种布局模式 CSS 实现
居右(默认)
默认 CSS Grid 布局,产品介绍在左,登录表单在右。
.auth-view--right { .auth-panel { justify-self: end; } }居左
利用 CSSdirection: rtl技巧反转 Grid 子元素顺序,使登录表单出现在左侧。
.auth-view--left { .auth-view__wrapper { direction: rtl; // 反转子元素排列方向 > * { direction: ltr; // 子元素内部文字方向恢复正常 } } .auth-panel { justify-self: start; } }为什么用direction: rtl而不是order?
order需要给每个子元素单独设置direction: rtl一行代码反转所有子元素,更简洁- 通过
> * { direction: ltr }确保内部文本不受影响
居中
隐藏产品介绍区域(通过v-if),wrapper 改为 flex 居中。
.auth-view--center { .auth-view__wrapper { display: flex; align-items: center; justify-content: center; } .auth-panel { justify-self: center; } }持久化方案
使用@vueuse/core的useStorage实现 localStorage 自动读写:
constauthLayout=useStorage<AuthLayout>("auth-layout","right");- 存储 key:
auth-layout - 默认值:
"right" - 类型安全:泛型约束为
AuthLayout = "left" | "center" | "right" - 自动同步:值变更时自动写入 localStorage,页面加载时自动读取
响应式适配
移动端(≤768px)自动隐藏产品介绍区域,登录表单全宽显示:
@media (max-width: 768px) { .auth-feature { display: none; } .auth-panel { width: 100%; } }工具栏在小屏(≤640px)固定在右上角:
@media (max-width: 640px) { .auth-view__toolbar { position: fixed; top: 12px; right: 16px; z-index: 20; } }踩坑记录
stylelintno-descending-specificity报错
问题:布局模式 CSS 块(.auth-view--left .auth-panel等)最初放在基础.auth-panel选择器之前,导致 stylelint 报错:
Expected selector ".auth-panel" to come before selector ".auth-view--left .auth-panel"原因:stylelint 的no-descending-specificity规则要求低特异性选择器必须出现在高特异性选择器之前。
解决:将布局模式块移到所有.auth-panel及其子选择器(.auth-panel__brand、.auth-panel__footer等)之后,@keyframes之前。
CSS 选择器正确顺序:
.auth-panel ← 基础选择器(先) .dark .auth-panel ← 主题变体 .auth-panel__brand ← 子选择器 .auth-panel__logo-wrap .auth-panel__logo ... .auth-panel__footer ← ↓ 布局模式块放在这里 ↓ .auth-view--left ← 包含 .auth-panel 的高特异性选择器(后) .auth-view--center .auth-view--right @keyframes ← 动画依赖
| 依赖 | 用途 |
|---|---|
@vueuse/core | useStorage持久化 |
@element-plus/icons-vue | Postcard/Tickets/CreditCard图标 |
element-plus | el-dropdown/el-tooltip组件 |
编程学习
技术分享
实战经验