refactor: ♻️ 布局选择组件代码优化
This commit is contained in:
@@ -1,35 +1,20 @@
|
||||
<template>
|
||||
<div class="flex flex-wrap justify-around w-full h-12">
|
||||
<el-tooltip content="左侧模式" placement="bottom">
|
||||
<div class="layout-select">
|
||||
<el-tooltip
|
||||
v-for="item in layoutOptions"
|
||||
:key="item.value"
|
||||
:content="item.label"
|
||||
placement="bottom"
|
||||
>
|
||||
<div
|
||||
class="layout-item left"
|
||||
:class="{ 'is-active': modelValue === LayoutEnum.LEFT }"
|
||||
@click="handleLayoutChange(LayoutEnum.LEFT)"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
:class="['layout-item', item.className, { 'is-active': modelValue === item.value }]"
|
||||
@click="handleLayoutChange(item.value)"
|
||||
@keydown.enter.space="handleLayoutChange(item.value)"
|
||||
>
|
||||
<div />
|
||||
<div />
|
||||
</div>
|
||||
</el-tooltip>
|
||||
|
||||
<el-tooltip content="顶部模式" placement="bottom">
|
||||
<div
|
||||
class="layout-item top"
|
||||
:class="{ 'is-active': modelValue === LayoutEnum.TOP }"
|
||||
@click="handleLayoutChange(LayoutEnum.TOP)"
|
||||
>
|
||||
<div />
|
||||
<div />
|
||||
</div>
|
||||
</el-tooltip>
|
||||
|
||||
<el-tooltip content="混合模式" placement="bottom">
|
||||
<div
|
||||
class="layout-item mix"
|
||||
:class="{ 'is-active': modelValue === LayoutEnum.MIX }"
|
||||
@click="handleLayoutChange(LayoutEnum.MIX)"
|
||||
>
|
||||
<div />
|
||||
<div />
|
||||
<div class="layout-item-part" />
|
||||
<div class="layout-item-part" />
|
||||
</div>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
@@ -38,76 +23,118 @@
|
||||
<script lang="ts" setup>
|
||||
import { LayoutEnum } from "@/enums/LayoutEnum";
|
||||
|
||||
const modelValue = defineModel("modelValue", {
|
||||
type: String,
|
||||
interface LayoutOption {
|
||||
value: LayoutEnum;
|
||||
label: string;
|
||||
className: string;
|
||||
}
|
||||
|
||||
const layoutOptions: LayoutOption[] = [
|
||||
{ value: LayoutEnum.LEFT, label: "左侧模式", className: "left" },
|
||||
{ value: LayoutEnum.TOP, label: "顶部模式", className: "top" },
|
||||
{ value: LayoutEnum.MIX, label: "混合模式", className: "mix" },
|
||||
];
|
||||
|
||||
const modelValue = defineModel<LayoutEnum>("modelValue", {
|
||||
required: true,
|
||||
default: () => "",
|
||||
default: () => LayoutEnum.LEFT,
|
||||
});
|
||||
|
||||
/**
|
||||
* 变换布局
|
||||
*
|
||||
* @param layout
|
||||
*/
|
||||
function handleLayoutChange(layout: string) {
|
||||
function handleLayoutChange(layout: LayoutEnum) {
|
||||
modelValue.value = layout;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.layout-selector {
|
||||
<style scoped lang="scss">
|
||||
.layout-select {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-around;
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
gap: 10px;
|
||||
justify-content: space-evenly;
|
||||
padding: 10px 0;
|
||||
--layout-primary: #1b2a47;
|
||||
--layout-background: #f0f2f5;
|
||||
--layout-shadow: 0 0 8px rgba(0, 0, 0, 0.1);
|
||||
--layout-hover: #e3f1f9;
|
||||
}
|
||||
|
||||
.layout-item {
|
||||
position: relative;
|
||||
width: 18%;
|
||||
height: 45px;
|
||||
overflow: hidden;
|
||||
height: 50px;
|
||||
cursor: pointer;
|
||||
background: #f0f2f5;
|
||||
border-radius: 4px;
|
||||
background: var(--layout-background);
|
||||
border-radius: 8px;
|
||||
box-shadow: var(--layout-shadow);
|
||||
|
||||
&.mix div:nth-child(1),
|
||||
&.top div:nth-child(1) {
|
||||
width: 100%;
|
||||
height: 30%;
|
||||
background: #1b2a47;
|
||||
box-shadow: 0 0 1px #888;
|
||||
transition:
|
||||
transform 0.2s ease,
|
||||
border-color 0.2s ease,
|
||||
box-shadow 0.2s ease;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--layout-hover);
|
||||
transform: scale(1.02); /* 稍微放大,避免过于夸张 */
|
||||
}
|
||||
|
||||
&.mix div:nth-child(2) {
|
||||
&:focus-visible {
|
||||
outline: 2px solid var(--el-color-primary);
|
||||
}
|
||||
|
||||
&-part {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 30%;
|
||||
height: 70%;
|
||||
background: #1b2a47;
|
||||
box-shadow: 0 0 1px #888;
|
||||
background: var(--layout-primary);
|
||||
border-radius: 4px; /* 保持和父容器一致的圆角 */
|
||||
box-shadow: var(--layout-shadow);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
&.left div:nth-child(1) {
|
||||
width: 30%;
|
||||
height: 100%;
|
||||
background: #1b2a47;
|
||||
&.left {
|
||||
.layout-item-part {
|
||||
&:first-child {
|
||||
width: 30%;
|
||||
height: 100%;
|
||||
border-radius: 4px 0 0 4px; /* 左边部分圆角 */
|
||||
}
|
||||
&:last-child {
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 70%;
|
||||
height: 30%;
|
||||
background: #fff;
|
||||
border-radius: 0 4px 4px 0; /* 右边部分圆角 */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.left div:nth-child(2) {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 70%;
|
||||
height: 30%;
|
||||
background: #fff;
|
||||
box-shadow: 0 0 1px #888;
|
||||
&.top {
|
||||
.layout-item-part:first-child {
|
||||
width: 100%;
|
||||
height: 30%;
|
||||
border-radius: 4px 4px 0 0; /* 顶部部分圆角 */
|
||||
}
|
||||
}
|
||||
|
||||
&.mix {
|
||||
.layout-item-part {
|
||||
&:first-child {
|
||||
width: 100%;
|
||||
height: 30%;
|
||||
border-radius: 4px 4px 0 0; /* 顶部部分圆角 */
|
||||
}
|
||||
&:last-child {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 30%;
|
||||
height: 70%;
|
||||
border-radius: 0 0 4px 4px; /* 底部部分圆角 */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.layout-item.is-active {
|
||||
.is-active {
|
||||
background-color: var(--layout-hover);
|
||||
border: 2px solid var(--el-color-primary);
|
||||
transform: scale(1.05); /* 轻微放大 */
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user