- 整体的左右(sider和main)布局使用的是flex布局,是为了方便sider能够收缩,右边的宽度能自动扩展,并且左边flex-shrink要设置为0,注意这种flex布局下,右边虽然能自动扩展,但是不能超过父容器的范围,需要加一个overflow:hidden,解释请看:flex布局左边宽度固定,右边宽度动态扩展问题
- 右边main使用上下布局,上面的main-header部分正常写就行了,下面的main-body使用了绝对定位,相对的是main这个容器,top就是main-header的高度,并且设置left:0,right:0,bottom:0,top:86px;这样就可以保证main-body是把main的剩余部分给占满,当然也可以直接写calc(100% - 86px),这样写的目的是为了让右边的整体不会出现浏览器的滚动条。
- main-body里面想要什么布局,就可以自己实现了,把路由出口放到main-body里面就行了
- flex布局真的是太方便了,管它什么布局,老子上来就是display:flex orz
<style lang="scss" scoped>
.layout {
display: flex;
}
* {
box-sizing: border-box;
}
.sider {
width: 220px;
height: 100vh;
background-color: #ddd;
position: relative;
flex-shrink: 0;
.sider-top {
height: 50px;
background-color: #bfa;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
}
.sider-body {
position: absolute;
top: 50px;
left: 0;
right: 0;
bottom: 0;
background-color: pink;
.li-item {
height: 50px;
margin: 10px;
background-color: grey;
color: #fff;
display: flex;
align-items: center;
justify-content: center;
}
}
}
.main {
flex: 1;
overflow: hidden;
position: relative;
.main-header {
.main-header-top {
height: 50px;
background: skyblue;
display: flex;
align-items: center;
padding: 0 10px;
}
.main-header-tags-wrapper {
background-color: lightsalmon;
padding: 0 10px;
.main-header-tags {
height: 36px;
display: flex;
align-items: center;
.tag-item {
width: 160px;
height: 26px;
margin-right: 10px;
background-color: #fff;
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: center;
}
}
}
}
.main-body {
position: absolute;
top: 86px;
left: 0;
right: 0;
bottom: 0;
background-color: rgb(211, 228, 243);
.main-content-wrapper {
overflow: auto;
box-sizing: border-box;
width: 100%;
height: 100%;
padding: 20px;
background-clip: content-box;
.content {
width: 100%;
height: 100%;
overflow: auto;
background-color: #fff;
border-radius: 8px;
padding: 10px 0 10px 10px;
box-sizing: border-box;
}
}
}
}
</style>
<template>
<div class="layout">
<div class="sider" :style="{ 'width': isExpand ? '220px' : '80px', transition: 'all 0.28s' }">
<div class="sider-top">
<h3 v-if="isExpand" style="white-space: nowrap;">后台管理系统</h3>
<el-icon v-else>
<Promotion />
</el-icon>
</div>
<div class="sider-body">
<el-scrollbar>
<ul>
<li class="li-item">1</li>
<li class="li-item">2</li>
<li class="li-item">3</li>
<li class="li-item">4</li>
<li class="li-item">5</li>
<li class="li-item">6</li>
<li class="li-item">7</li>
<li class="li-item">8</li>
<li class="li-item">9</li>
<li class="li-item">9</li>
<li class="li-item">9</li>
<li class="li-item">9</li>
<li class="li-item">9</li>
</ul>
</el-scrollbar>
</div>
</div>
<div class="main">
<div class="main-header">
<div class="main-header-top">
<el-button type="primary" @click="toggleSider" :icon="isExpand ? Expand : Fold" color="white"
style="font-size:1.3em" text />
</div>
<div class="main-header-tags-wrapper">
<el-scrollbar>
<div class="main-header-tags">
<div class="tag-item">1</div>
<div class="tag-item">2</div>
<div class="tag-item">3</div>
<div class="tag-item">4</div>
<div class="tag-item">5</div>
<div class="tag-item">6</div>
<div class="tag-item">7</div>
<div class="tag-item">8</div>
<div class="tag-item">9</div>
</div>
</el-scrollbar>
</div>
</div>
<div class="main-body">
<div class="main-content-wrapper">
<div class="content">
<el-scrollbar>
<el-timeline>
<el-timeline-item v-for="(activity, index) in activities" :key="index" :icon="activity.icon"
:type="activity.type" :color="activity.color" :size="activity.size"
:hollow="activity.hollow" :timestamp="activity.timestamp">
{{ activity.content }}
</el-timeline-item>
</el-timeline>
</el-scrollbar>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, reactive } from 'vue'
import { Expand, Fold, MoreFilled } from '@element-plus/icons-vue'
const isExpand = ref(true)
const toggleSider = () => {
isExpand.value = !isExpand.value
}
const activities = [
{
content: 'Custom icon',
timestamp: '2018-04-12 20:46',
size: 'large',
type: 'primary',
icon: MoreFilled,
},
{
content: 'Custom icon',
timestamp: '2018-04-12 20:46',
size: 'large',
type: 'primary',
icon: MoreFilled,
},
{
content: 'Custom icon',
timestamp: '2018-04-12 20:46',
size: 'large',
type: 'primary',
icon: MoreFilled,
},
{
content: 'Custom icon',
timestamp: '2018-04-12 20:46',
size: 'large',
type: 'primary',
icon: MoreFilled,
},
{
content: 'Custom icon',
timestamp: '2018-04-12 20:46',
size: 'large',
type: 'primary',
icon: MoreFilled,
},
{
content: 'Custom icon',
timestamp: '2018-04-12 20:46',
size: 'large',
type: 'primary',
icon: MoreFilled,
},
{
content: 'Custom icon',
timestamp: '2018-04-12 20:46',
size: 'large',
type: 'primary',
icon: MoreFilled,
},
{
content: 'Custom icon',
timestamp: '2018-04-12 20:46',
size: 'large',
type: 'primary',
icon: MoreFilled,
},
{
content: 'Custom icon',
timestamp: '2018-04-12 20:46',
size: 'large',
type: 'primary',
icon: MoreFilled,
},
{
content: 'Custom icon',
timestamp: '2018-04-12 20:46',
size: 'large',
type: 'primary',
icon: MoreFilled,
},
{
content: 'Custom icon',
timestamp: '2018-04-12 20:46',
size: 'large',
type: 'primary',
icon: MoreFilled,
}, {
content: 'Custom icon',
timestamp: '2018-04-12 20:46',
size: 'large',
type: 'primary',
icon: MoreFilled,
},
]
</script>