vue3:十一、主页面布局(左侧菜单折叠展开设置)

发布于:2025-03-23 ⋅ 阅读:(29) ⋅ 点赞:(0)

一、实现效果

二、基本实现

1、菜单容器增加展开收缩方法

在菜单容器中开启这个方法,值设置为一个变量

 :collapse='iscollapse'

2、定义菜单收缩与否的变量

在js中初始化是否收缩的变量,初始值为不收缩(也就是展开)

//左侧菜单展开与收缩
const iscollapse = ref(true);//默认不收缩

 3、设置一个按钮可管控是否收缩

在header中设置一个按钮,给一个点击事件,去控制是否收缩

<span @click="toggleSideBar">
    展开/收缩
</span>

 4、定义收缩展开方法

在js中写入是否收缩的逻辑,如果点击,就将是否收缩的变量值设置为相反(例如:现在是展开状态,点击一次就收缩,再点一次就展开)

//点击按钮实现收缩还是展开
const toggleSideBar = () => {
  iscollapse.value = !iscollapse.value;
}

5、需改左侧菜单的动态宽度

在aside中,增加一个初始的css为sidebar,再增加一个根据变量设置的样式is-short

如果iscollapse为true就执行is-short样式,也就是在收缩的时候aside的样式会有一个is-short

固定展开宽度为200px, 给一个宽度的过度效果为0.3秒,收缩的宽度设置为60px

6、修改视图层存在的问题

这是没修改视图层之前的效果,发现折叠后,标题还没有完全被隐藏

修改:给标题增加span标签

三、完整代码

src/layout/index.vue

<template>
  <el-container class="layout-container-demo" style="height: 100vh">
    <el-aside :class="{ 'is-short': iscollapse }" class="sidebar">
      <el-scrollbar>
        <!-- default-openeds:默认展开菜单 -->
        <!-- default-active:默认选中菜单 -->
         <!-- collapse:是否折叠菜单 -->
        <el-menu :default-active="activeMenu" :router="true" :collapse='iscollapse'>
          <!-- 遍历一级菜单 -->
          <template v-for="(item, index) in menu" :key="index">
            <!-- 如果一级菜单有子菜单,渲染 el-sub-menu -->
            <el-sub-menu v-if="item.children && item.children.length > 0" :index="`${index + 1}`">
              <template #title>
                <el-icon v-if="item.icon">
                  <component :is="item.icon" />
                </el-icon>
                <span>{{ item.name }}</span>
              </template>
              <!-- 遍历二级菜单 -->
              <el-menu-item v-for="(secondmenu, secondindex) in item.children" :key="secondindex"
                :index="secondmenu.path">
                <span>{{ secondmenu.name }}</span>
              </el-menu-item>
            </el-sub-menu>
            <!-- 如果一级菜单没有子菜单,渲染 el-menu-item -->
            <el-menu-item v-else :index="item.path">
              <el-icon v-if="item.icon">
                <component :is="item.icon" />
              </el-icon>
              <span>{{ item.name }}</span>
            </el-menu-item>
          </template>
        </el-menu>
      </el-scrollbar>
    </el-aside>

    <el-container>
      <el-header style="font-size: 12px">
        <span @click="toggleSideBar">
          展开/收缩
        </span>
        <div class="toolbar">
          <el-dropdown>
            <el-icon style="margin-right: 8px; margin-top: 1px">
              <setting />
            </el-icon>
            <template #dropdown>
              <el-dropdown-menu>
                <el-dropdown-item>View</el-dropdown-item>
                <el-dropdown-item>Add</el-dropdown-item>
                <el-dropdown-item>Delete</el-dropdown-item>
              </el-dropdown-menu>
            </template>
          </el-dropdown>
          <span>Tom</span>
        </div>
      </el-header>
      <!-- 右侧内容 -->
      <el-main>
        <el-scrollbar>
          <RouterView />
        </el-scrollbar>
      </el-main>
      <!-- 底部信息 -->
      <el-footer class="flex flex-center">
        <span>@2025-2030 wen</span>
      </el-footer>
    </el-container>
  </el-container>
</template>

<script setup>
import { ref, reactive } from 'vue'
import { useRoute } from 'vue-router'

//获取当前页面路径
const route = useRoute();
const currentPath = route.path;
const activeMenu = ref(currentPath);

//左侧菜单展开与收缩
const iscollapse = ref(true);//默认不收缩
//点击按钮实现收缩还是展开
const toggleSideBar = () => {
  iscollapse.value = !iscollapse.value;
}
// 菜单
const menu = reactive([
  {
    name: 'Navigator One',
    icon: "message",
    path: '/about',
  },
  {
    name: 'Navigator Two',
    icon: "message",
    children: [
      {
        name: 'Option 1',
        path: '/home',
      },
      {
        name: 'Option 2',
      },
      {
        name: 'Option 3',
      },
      {
        name: 'Option 4',
      },
    ]
  },
]);

</script>

<style scoped>
.layout-container-demo .el-header {
  position: relative;
  background-color: var(--el-color-primary-light-7);
  color: var(--el-text-color-primary);
}

.layout-container-demo .el-aside {
  color: var(--el-text-color-primary);
  background: var(--el-color-primary-light-8);
}

.layout-container-demo .el-menu {
  border-right: none;
}

.layout-container-demo .el-main {
  padding: 0;
}

.layout-container-demo .toolbar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 100%;
  right: 20px;
}

/* 左侧菜单宽度设置 */
.sidebar {
  width: 200px;
  transition: width .3s;
}

.is-short {
  width: 60px;
}
</style>