Giter VIP home page Giter VIP logo

Comments (9)

xiaoxian521 avatar xiaoxian521 commented on June 1, 2024

提供截图和复现仓库 而不是压缩包

from vue-pure-admin.

beiTiao-lys avatar beiTiao-lys commented on June 1, 2024

image
image

from vue-pure-admin.

beiTiao-lys avatar beiTiao-lys commented on June 1, 2024

https://yiming_chang.gitee.io/vue-pure-admin/#/components/message 地址为在线演示地址

from vue-pure-admin.

xiaoxian521 avatar xiaoxian521 commented on June 1, 2024

这并非平台问题 el-menu 折叠后本身就不支持滚动 或许你可以尝试用样式使其支持
image

from vue-pure-admin.

beiTiao-lys avatar beiTiao-lys commented on June 1, 2024

基于昨天的问题我询问了element的官方, 他们给出了一个可行的解决方案, 即在el-menu-item组件的外层嵌套一个 el-menu-item-group并给组件设置max-heightoverflow-y属性可以解决这个问题, 可我在Pure Admin的源码中并未发现相关的处理, 在我看来这确实属于一个代码的bug,若能做出相应更改的话, 会很棒
image

from vue-pure-admin.

xiaoxian521 avatar xiaoxian521 commented on June 1, 2024

Welcome to PR

from vue-pure-admin.

xiaoxian521 avatar xiaoxian521 commented on June 1, 2024

src/layout/components/sidebar/sidebarItem.vue 文件改为下面代码

<script setup lang="ts">
import path from "path";
import { getConfig } from "@/config";
import { menuType } from "../../types";
import extraIcon from "./extraIcon.vue";
import { useWindowSize } from "@vueuse/core";
import { useNav } from "@/layout/hooks/useNav";
import { transformI18n } from "@/plugins/i18n";
import { useRenderIcon } from "@/components/ReIcon/src/hooks";
import { ref, toRaw, PropType, nextTick, computed, CSSProperties } from "vue";

import ArrowUp from "@iconify-icons/ep/arrow-up-bold";
import EpArrowDown from "@iconify-icons/ep/arrow-down-bold";
import ArrowLeft from "@iconify-icons/ep/arrow-left-bold";
import ArrowRight from "@iconify-icons/ep/arrow-right-bold";

const { height } = useWindowSize();
const { layout, isCollapse, tooltipEffect, getDivStyle } = useNav();

const props = defineProps({
  item: {
    type: Object as PropType<menuType>
  },
  isNest: {
    type: Boolean,
    default: false
  },
  basePath: {
    type: String,
    default: ""
  }
});

const getSpanStyle = computed((): CSSProperties => {
  return {
    width: "100%",
    textAlign: "center"
  };
});

const getNoDropdownStyle = computed((): CSSProperties => {
  return {
    display: "flex",
    alignItems: "center"
  };
});

const getMenuTextStyle = computed(() => {
  return {
    overflow: "hidden",
    textOverflow: "ellipsis",
    outline: "none"
  };
});

const getsubMenuIconStyle = computed((): CSSProperties => {
  return {
    display: "flex",
    justifyContent: "center",
    alignItems: "center",
    margin:
      layout.value === "horizontal"
        ? "0 5px 0 0"
        : isCollapse.value
        ? "0 auto"
        : "0 5px 0 0"
  };
});

const getSubTextStyle = computed((): CSSProperties => {
  if (!isCollapse.value) {
    return {
      width: "210px",
      display: "inline-block",
      overflow: "hidden",
      textOverflow: "ellipsis"
    };
  } else {
    return {
      width: ""
    };
  }
});

const getSubMenuDivStyle = computed((): any => {
  return item => {
    return !isCollapse.value
      ? {
          width: "100%",
          display: "flex",
          alignItems: "center",
          justifyContent: "space-between",
          overflow: "hidden"
        }
      : {
          width: "100%",
          textAlign:
            item?.parentId === null
              ? "center"
              : layout.value === "mix" && item?.pathList?.length === 2
              ? "center"
              : ""
        };
  };
});

const expandCloseIcon = computed(() => {
  if (!getConfig()?.MenuArrowIconNoTransition) return "";
  return {
    "expand-close-icon": useRenderIcon(EpArrowDown),
    "expand-open-icon": useRenderIcon(ArrowUp),
    "collapse-close-icon": useRenderIcon(ArrowRight),
    "collapse-open-icon": useRenderIcon(ArrowLeft)
  };
});

const onlyOneChild: menuType = ref(null);
// 存放菜单是否存在showTooltip属性标识
const hoverMenuMap = new WeakMap();
// 存储菜单文本dom元素
const menuTextRef = ref(null);

function hoverMenu(key) {
  // 如果当前菜单showTooltip属性已存在,退出计算
  if (hoverMenuMap.get(key)) return;

  nextTick(() => {
    // 如果文本内容的整体宽度大于其可视宽度,则文本溢出
    menuTextRef.value?.scrollWidth > menuTextRef.value?.clientWidth
      ? Object.assign(key, {
          showTooltip: true
        })
      : Object.assign(key, {
          showTooltip: false
        });
    hoverMenuMap.set(key, true);
  });
}

// 左侧菜单折叠后,当菜单没有图标时只显示第一个文字并加上省略号
function overflowSlice(text, item?: any) {
  const newText =
    (text?.length > 1 ? text.toString().slice(0, 1) : text) + "...";
  if (item && !(isCollapse.value && item?.parentId === null)) {
    return layout.value === "mix" &&
      item?.pathList?.length === 2 &&
      isCollapse.value
      ? newText
      : text;
  }
  return newText;
}

function hasOneShowingChild(children: menuType[] = [], parent: menuType) {
  const showingChildren = children.filter((item: any) => {
    onlyOneChild.value = item;
    return true;
  });

  if (showingChildren[0]?.meta?.showParent) {
    return false;
  }

  if (showingChildren.length === 1) {
    return true;
  }

  if (showingChildren.length === 0) {
    onlyOneChild.value = { ...parent, path: "", noShowingChildren: true };
    return true;
  }
  return false;
}

function resolvePath(routePath) {
  const httpReg = /^http(s?):\/\//;
  if (httpReg.test(routePath) || httpReg.test(props.basePath)) {
    return routePath || props.basePath;
  } else {
    // 使用path.posix.resolve替代path.resolve 避免windows环境下使用electron出现盘符问题
    return path.posix.resolve(props.basePath, routePath);
  }
}
</script>

<template>
  <el-menu-item
    v-if="
      hasOneShowingChild(props.item.children, props.item) &&
      (!onlyOneChild.children || onlyOneChild.noShowingChildren)
    "
    :index="resolvePath(onlyOneChild.path)"
    :class="{ 'submenu-title-noDropdown': !isNest }"
    :style="getNoDropdownStyle"
  >
    <div
      v-if="toRaw(props.item.meta.icon)"
      class="sub-menu-icon"
      :style="getsubMenuIconStyle"
    >
      <component
        :is="
          useRenderIcon(
            toRaw(onlyOneChild.meta.icon) ||
              (props.item.meta && toRaw(props.item.meta.icon))
          )
        "
      />
    </div>
    <span
      v-if="
        !props.item?.meta.icon &&
        isCollapse &&
        layout === 'vertical' &&
        props.item?.pathList?.length === 1
      "
      :style="getSpanStyle"
    >
      {{ overflowSlice(transformI18n(onlyOneChild.meta.title)) }}
    </span>
    <span
      v-if="
        !onlyOneChild.meta.icon &&
        isCollapse &&
        layout === 'mix' &&
        props.item?.pathList?.length === 2
      "
      :style="getSpanStyle"
    >
      {{ overflowSlice(transformI18n(onlyOneChild.meta.title)) }}
    </span>
    <template #title>
      <div :style="getDivStyle">
        <span v-if="layout === 'horizontal'">
          {{ transformI18n(onlyOneChild.meta.title) }}
        </span>
        <el-tooltip
          v-else
          placement="top"
          :effect="tooltipEffect"
          :offset="-10"
          :disabled="!onlyOneChild.showTooltip"
        >
          <template #content>
            {{ transformI18n(onlyOneChild.meta.title) }}
          </template>
          <span
            ref="menuTextRef"
            :style="getMenuTextStyle"
            @mouseover="hoverMenu(onlyOneChild)"
          >
            {{ transformI18n(onlyOneChild.meta.title) }}
          </span>
        </el-tooltip>
        <extraIcon :extraIcon="onlyOneChild.meta.extraIcon" />
      </div>
    </template>
  </el-menu-item>

  <el-sub-menu
    v-else
    ref="subMenu"
    v-bind="expandCloseIcon"
    :index="resolvePath(props.item.path)"
  >
    <template #title>
      <div
        v-if="toRaw(props.item.meta.icon)"
        :style="getsubMenuIconStyle"
        class="sub-menu-icon"
      >
        <component
          :is="useRenderIcon(props.item.meta && toRaw(props.item.meta.icon))"
        />
      </div>
      <span v-if="layout === 'horizontal'">
        {{ transformI18n(props.item.meta.title) }}
      </span>
      <div
        :style="getSubMenuDivStyle(props.item)"
        v-if="
          !(
            isCollapse &&
            toRaw(props.item.meta.icon) &&
            props.item.parentId === null
          )
        "
      >
        <el-tooltip
          v-if="layout !== 'horizontal'"
          placement="top"
          :effect="tooltipEffect"
          :offset="-10"
          :disabled="!props.item.showTooltip"
        >
          <template #content>
            {{ transformI18n(props.item.meta.title) }}
          </template>
          <span
            ref="menuTextRef"
            :style="getSubTextStyle"
            @mouseover="hoverMenu(props.item)"
          >
            {{
              overflowSlice(transformI18n(props.item.meta.title), props.item)
            }}
          </span>
        </el-tooltip>
        <extraIcon v-if="!isCollapse" :extraIcon="props.item.meta.extraIcon" />
      </div>
    </template>
    <el-scrollbar
      v-if="layout !== 'horizontal'"
      class="sidebar-scrollbar"
      :max-height="`${height - 18}px`"
    >
      <sidebar-item
        v-for="child in props.item.children"
        :key="child.path"
        :is-nest="true"
        :item="child"
        :base-path="resolvePath(child.path)"
        class="nest-menu"
      />
    </el-scrollbar>
    <template v-else>
      <sidebar-item
        v-for="child in props.item.children"
        :key="child.path"
        :is-nest="true"
        :item="child"
        :base-path="resolvePath(child.path)"
        class="nest-menu"
      />
    </template>
  </el-sub-menu>
</template>

<style scoped>
.sidebar-scrollbar {
  overflow: visible;
}
</style>

但这并不是最优解,如果el-menu折叠后,本身就支持el-scrollbar会更好

from vue-pure-admin.

xiaoxian521 avatar xiaoxian521 commented on June 1, 2024

改动对比

image image

from vue-pure-admin.

xiaoxian521 avatar xiaoxian521 commented on June 1, 2024

完美解决

from vue-pure-admin.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.