|
|
@@ -0,0 +1,194 @@
|
|
|
+<template>
|
|
|
+ <!-- 左侧折叠面板 -->
|
|
|
+ <transition name="drawer-slide">
|
|
|
+ <div class="left-group">
|
|
|
+ <el-row class="tac">
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-menu
|
|
|
+ :default-active="currentActiveIndex"
|
|
|
+ class="el-menu-vertical-demo"
|
|
|
+ @open="handleOpen"
|
|
|
+ @close="handleClose"
|
|
|
+ >
|
|
|
+ <el-menu-item
|
|
|
+ v-for="(item, index) in groupList"
|
|
|
+ :key="index"
|
|
|
+ :index="index.toString()"
|
|
|
+ @click="navigateToAI(item)"
|
|
|
+ v-model="currentActiveIndex"
|
|
|
+ @mouseover="item.isHover = true"
|
|
|
+ @mouseout="item.isHover = false"
|
|
|
+ >
|
|
|
+ <!-- 根据状态切换图片-->
|
|
|
+ <img
|
|
|
+ :src="currentActiveIndex === index.toString() || item.isHover ? item.hoverIcon : item.icon"
|
|
|
+ alt=""
|
|
|
+ class="menu-icon"
|
|
|
+ />
|
|
|
+ {{ item.title }}
|
|
|
+ </el-menu-item>
|
|
|
+ </el-menu>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ </div>
|
|
|
+ </transition>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup>
|
|
|
+import { ref, onMounted,watch} from 'vue'
|
|
|
+import { useRouter, useRoute } from 'vue-router'
|
|
|
+
|
|
|
+
|
|
|
+// 导入图片 白色
|
|
|
+import blockly from '@/assets/icon/blockly.png'
|
|
|
+// 黑色
|
|
|
+import blockly02 from '@/assets/icon/blockly02.png'
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+const router = useRouter()
|
|
|
+const route = useRoute()
|
|
|
+
|
|
|
+// 添加抽屉显示状态
|
|
|
+const drawerVisible = ref(true)
|
|
|
+// 当前选中索引状态
|
|
|
+const currentActiveIndex = ref('2')
|
|
|
+
|
|
|
+// 渲染侧边栏
|
|
|
+const groupList = ref([
|
|
|
+ {
|
|
|
+ icon: blockly,
|
|
|
+ hoverIcon: blockly02,
|
|
|
+ title: 'blockly编程'
|
|
|
+ }
|
|
|
+])
|
|
|
+
|
|
|
+
|
|
|
+// 提取更新选中状态的逻辑为单独函数
|
|
|
+// 优化后的更新选中状态的方法
|
|
|
+const updateActiveIndex = () => {
|
|
|
+ const path = route.path;
|
|
|
+ // 使用映射表存储路径和索引的对应关系
|
|
|
+ const pathIndexMap = {
|
|
|
+ 'programming':"0" // 编程课
|
|
|
+ };
|
|
|
+ // 查找路径对应的索引
|
|
|
+ for (const [key, index] of Object.entries(pathIndexMap)) {
|
|
|
+ if (path.includes(key)) {
|
|
|
+ currentActiveIndex.value = index;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// 组件挂载时确保默认选中状态
|
|
|
+onMounted(() => {
|
|
|
+ updateActiveIndex();
|
|
|
+});
|
|
|
+
|
|
|
+// 添加路由变化监听,更新选中状态
|
|
|
+watch(() => route, () => {
|
|
|
+ updateActiveIndex();
|
|
|
+}, { immediate: true, deep: true });
|
|
|
+
|
|
|
+// 跳转智能问答
|
|
|
+const navigateToAI = async (group) => {
|
|
|
+ if (group.title === 'blockly编程') {
|
|
|
+ router.push('/programming')
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 处理菜单展开和关闭
|
|
|
+const handleOpen = () => {}
|
|
|
+const handleClose = () => {}
|
|
|
+
|
|
|
+// 导出状态和方法供父组件使用
|
|
|
+defineExpose({
|
|
|
+ drawerVisible,
|
|
|
+ toggleDrawer: () => {
|
|
|
+ drawerVisible.value = !drawerVisible.value
|
|
|
+ }
|
|
|
+})
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped lang="scss">
|
|
|
+@use 'sass:math';
|
|
|
+// 定义rpx转换函数
|
|
|
+@function rpx($px) {
|
|
|
+ @return math.div($px, 750) * 100vw;
|
|
|
+}
|
|
|
+/* 添加过渡样式 */
|
|
|
+::v-deep .drawer-slide-enter-active,
|
|
|
+::v-deep .drawer-slide-leave-active {
|
|
|
+ transition: all 0.3s ease;
|
|
|
+}
|
|
|
+::v-deep .drawer-slide-enter-from,
|
|
|
+::v-deep .drawer-slide-leave-to {
|
|
|
+ transform: translateX(-100%);
|
|
|
+ opacity: 0;
|
|
|
+}
|
|
|
+
|
|
|
+// 侧边栏
|
|
|
+.left-group {
|
|
|
+ width: rpx(135);
|
|
|
+ height: 100%;
|
|
|
+ background: linear-gradient(to bottom, #001169, #8a78d0);
|
|
|
+ overflow-y: auto;
|
|
|
+ // 自定义滚动条样式
|
|
|
+ &::-webkit-scrollbar {
|
|
|
+ width: rpx(0); // 滚动条宽度
|
|
|
+ }
|
|
|
+ &::-webkit-scrollbar-track {
|
|
|
+ background-color: rgba(255, 255, 255, 0.1); // 滚动条轨道背景色
|
|
|
+ border-radius: rpx(2); // 滚动条轨道圆角
|
|
|
+ }
|
|
|
+ &::-webkit-scrollbar-thumb {
|
|
|
+ background-color: rgba(255, 255, 255, 0.3); // 滚动条滑块颜色
|
|
|
+ border-radius: rpx(2); // 滚动条滑块圆角
|
|
|
+ transition: background-color 0.3s ease; // 滑块颜色过渡效果
|
|
|
+ }
|
|
|
+ &::-webkit-scrollbar-thumb:hover {
|
|
|
+ background-color: rgba(255, 255, 255, 0.5); // 鼠标悬停时的滑块颜色
|
|
|
+ }
|
|
|
+}
|
|
|
+.mb-2 {
|
|
|
+ color: black;
|
|
|
+ margin-top: rpx(1);
|
|
|
+}
|
|
|
+.tac ::v-deep(.el-menu) {
|
|
|
+ background-color: transparent;
|
|
|
+ border: none;
|
|
|
+ width: 100%;
|
|
|
+ margin-top: rpx(25);
|
|
|
+ margin-left: rpx(10);
|
|
|
+}
|
|
|
+.el-menu-item {
|
|
|
+ width: rpx(115);
|
|
|
+ height: rpx(25);
|
|
|
+ margin-bottom: rpx(5);
|
|
|
+ border-radius: rpx(6);
|
|
|
+ color: white;
|
|
|
+ font-size: rpx(8);
|
|
|
+}
|
|
|
+.el-menu-item .el-icon svg {
|
|
|
+ font-size: rpx(15);
|
|
|
+ color: white;
|
|
|
+}
|
|
|
+.el-menu .el-menu-item:hover {
|
|
|
+ background: linear-gradient(to bottom, #ffefb0, #ffcc00);
|
|
|
+ box-shadow: 0 8px 8px rgb(0, 0, 0, 0.3);
|
|
|
+ color: black;
|
|
|
+ font-size: rpx(8);
|
|
|
+}
|
|
|
+:deep(.el-menu .el-menu-item.is-active) {
|
|
|
+ background: linear-gradient(to bottom, #fee78a, #ffce1b);
|
|
|
+ color: black;
|
|
|
+ font-size: rpx(8);
|
|
|
+ box-shadow: 0 4px 8px rgba(3, 3, 3, 0.3);
|
|
|
+}
|
|
|
+.menu-icon {
|
|
|
+ width: rpx(11);
|
|
|
+ height: rpx(11);
|
|
|
+ margin-right: rpx(2);
|
|
|
+}
|
|
|
+</style>
|