Переглянути джерело

fix(menu): top submenu disappeared problem #214

vben 4 роки тому
батько
коміт
0ec1a62e59

+ 1 - 0
CHANGELOG.zh_CN.md

@@ -15,6 +15,7 @@
 - 修复 form 表单初始化值为 0 问题
 - 修复表格换行问题
 - 修复菜单外链不跳转
+- 修复菜单顶部显示问题
 
 ## 2.0.0-rc.17 (2020-01-18)
 

+ 2 - 1
build/config/lessModifyVars.ts

@@ -1,7 +1,8 @@
 /**
  * less global variable
  */
-const primaryColor = '#018ffb';
+const primaryColor = '#0084f4';
+// const primaryColor = '#018ffb';
 // const primaryColor = '#0065cc';
 //{
 const modifyVars = {

+ 1 - 1
package.json

@@ -64,7 +64,7 @@
     "@typescript-eslint/eslint-plugin": "^4.14.0",
     "@typescript-eslint/parser": "^4.14.0",
     "@vitejs/plugin-legacy": "^1.2.1",
-    "@vitejs/plugin-vue": "^1.1.2",
+    "@vitejs/plugin-vue": "1.1.0",
     "@vitejs/plugin-vue-jsx": "^1.0.2",
     "@vue/compiler-sfc": "^3.0.5",
     "@vuedx/typecheck": "^0.6.0",

+ 8 - 15
src/components/Menu/src/BasicMenu.vue

@@ -13,13 +13,7 @@
     v-bind="getInlineCollapseOptions"
   >
     <template v-for="item in items" :key="item.path">
-      <BasicSubMenuItem
-        :item="item"
-        :theme="theme"
-        :level="1"
-        :showTitle="showTitle"
-        :isHorizontal="isHorizontal"
-      />
+      <BasicSubMenuItem :item="item" :theme="theme" :isHorizontal="isHorizontal" />
     </template>
   </Menu>
 </template>
@@ -46,6 +40,7 @@
 
   // import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
   import { listenerLastChangeTab } from '/@/logics/mitt/tabChange';
+  import { getAllParentPath } from '/@/router/helper/menuHelper';
 
   export default defineComponent({
     name: 'BasicMenu',
@@ -96,16 +91,12 @@
           prefixCls,
           `justify-${align}`,
           {
-            [`${prefixCls}--hide-title`]: !unref(showTitle),
-            [`${prefixCls}--collapsed-show-title`]: props.collapsedShowTitle,
             [`${prefixCls}__second`]: !props.isHorizontal && unref(getSplit),
             [`${prefixCls}__sidebar-hor`]: unref(getIsTopMenu),
           },
         ];
       });
 
-      const showTitle = computed(() => props.collapsedShowTitle && unref(getCollapsed));
-
       const getInlineCollapseOptions = computed(() => {
         const isInline = props.mode === MenuModeEnum.INLINE;
 
@@ -135,7 +126,7 @@
           }
         );
 
-      async function handleMenuClick({ key, keyPath }: { key: string; keyPath: string[] }) {
+      async function handleMenuClick({ key }: { key: string; keyPath: string[] }) {
         const { beforeClickFn } = props;
         if (beforeClickFn && isFunction(beforeClickFn)) {
           const flag = await beforeClickFn(key);
@@ -144,7 +135,9 @@
         emit('menuClick', key);
 
         isClickGo.value = true;
-        menuState.openKeys = keyPath;
+        // const parentPath = await getCurrentParentPath(key);
+
+        // menuState.openKeys = [parentPath];
         menuState.selectedKeys = [key];
       }
 
@@ -160,7 +153,8 @@
           const parentPath = await getCurrentParentPath(path);
           menuState.selectedKeys = [parentPath];
         } else {
-          menuState.selectedKeys = [path];
+          const parentPaths = await getAllParentPath(props.items, path);
+          menuState.selectedKeys = parentPaths;
         }
       }
 
@@ -172,7 +166,6 @@
         getMenuClass,
         handleOpenChange,
         getOpenKeys,
-        showTitle,
         ...toRefs(menuState),
       };
     },

+ 11 - 9
src/components/Menu/src/components/BasicMenuItem.vue

@@ -1,10 +1,11 @@
 <template>
-  <MenuItem :class="getLevelClass">
+  <MenuItem>
+    <!-- <MenuItem :class="getLevelClass"> -->
     <MenuItemContent v-bind="$props" :item="item" />
   </MenuItem>
 </template>
 <script lang="ts">
-  import { defineComponent, computed } from 'vue';
+  import { defineComponent } from 'vue';
   import { Menu } from 'ant-design-vue';
   import { useDesign } from '/@/hooks/web/useDesign';
   import { itemProps } from '../props';
@@ -14,18 +15,19 @@
     name: 'BasicMenuItem',
     components: { MenuItem: Menu.Item, MenuItemContent },
     props: itemProps,
-    setup(props) {
+    setup() // props
+    {
       const { prefixCls } = useDesign('basic-menu-item');
 
-      const getLevelClass = computed(() => {
-        const { level, theme } = props;
+      // const getLevelClass = computed(() => {
+      //   const { level, theme } = props;
 
-        const levelCls = [`${prefixCls}__level${level}`, theme];
-        return levelCls;
-      });
+      //   const levelCls = [`${prefixCls}__level${level}`, theme];
+      //   return levelCls;
+      // });
       return {
         prefixCls,
-        getLevelClass,
+        // getLevelClass,
       };
     },
   });

+ 3 - 7
src/components/Menu/src/components/BasicSubMenuItem.vue

@@ -2,17 +2,15 @@
   <BasicMenuItem v-if="!menuHasChildren(item) && getShowMenu" v-bind="$props" />
   <SubMenu
     v-if="menuHasChildren(item) && getShowMenu"
-    :class="[`${prefixCls}__level${level}`, theme]"
+    :class="[theme]"
+    popupClassName="app-top-menu-popup"
   >
     <template #title>
       <MenuItemContent v-bind="$props" :item="item" />
     </template>
-    <!-- <template #expandIcon="{ key }">
-      <ExpandIcon :key="key" />
-    </template> -->
 
     <template v-for="childrenItem in item.children || []" :key="childrenItem.path">
-      <BasicSubMenuItem v-bind="$props" :item="childrenItem" :level="level + 1" />
+      <BasicSubMenuItem v-bind="$props" :item="childrenItem" />
     </template>
   </SubMenu>
 </template>
@@ -26,7 +24,6 @@
   import BasicMenuItem from './BasicMenuItem.vue';
   import MenuItemContent from './MenuItemContent.vue';
 
-  // import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
   export default defineComponent({
     name: 'BasicSubMenuItem',
     isSubMenu: true,
@@ -35,7 +32,6 @@
       SubMenu: Menu.SubMenu,
       MenuItem: Menu.Item,
       MenuItemContent,
-      // ExpandIcon: createAsyncComponent(() => import('./ExpandIcon.vue')),
     },
     props: itemProps,
     setup(props) {

+ 4 - 11
src/components/Menu/src/components/MenuItemContent.vue

@@ -1,10 +1,7 @@
 <template>
   <span :class="`${prefixCls}-wrapper`">
     <Icon v-if="getIcon" :icon="getIcon" :size="18" :class="`${prefixCls}-wrapper__icon`" />
-    <span :class="getNameClass">
-      {{ getI18nName }}
-      <MenuItemTag v-bind="$props" />
-    </span>
+    {{ getI18nName }}
   </span>
 </template>
 <script lang="ts">
@@ -14,25 +11,21 @@
   import { useI18n } from '/@/hooks/web/useI18n';
   import { useDesign } from '/@/hooks/web/useDesign';
   import { contentProps } from '../props';
-  import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
   const { t } = useI18n();
 
   export default defineComponent({
     name: 'MenuItemContent',
-    components: { Icon, MenuItemTag: createAsyncComponent(() => import('./MenuItemTag.vue')) },
+    components: {
+      Icon,
+    },
     props: contentProps,
     setup(props) {
       const { prefixCls } = useDesign('basic-menu-item-content');
       const getI18nName = computed(() => t(props.item?.name));
       const getIcon = computed(() => props.item?.icon);
 
-      const getNameClass = computed(() => {
-        const { showTitle } = props;
-        return { [`${prefixCls}--show-title`]: showTitle, [`${prefixCls}__name`]: !showTitle };
-      });
       return {
         prefixCls,
-        getNameClass,
         getI18nName,
         getIcon,
       };

+ 2 - 290
src/components/Menu/src/index.less

@@ -1,129 +1,12 @@
 @basic-menu-prefix-cls: ~'@{namespace}-basic-menu';
-@basic-menu-content-prefix-cls: ~'@{namespace}-basic-menu-item-content';
-@basic-menu-tag-prefix-cls: ~'@{namespace}-basic-menu-item-tag';
 
-.active-style() {
-  color: @white;
-  // background: @primary-color !important;
-  background: linear-gradient(
-    118deg,
-    rgba(@primary-color, 0.8),
-    rgba(@primary-color, 1)
-  ) !important;
-}
-
-.active-menu-style() {
-  .ant-menu-item-selected,
-  .ant-menu-submenu-popup.ant-menu-dark .ant-menu-item-selected {
-    .active-style();
-  }
+.app-top-menu-popup {
+  min-width: 150px;
 }
 
 .@{basic-menu-prefix-cls} {
   width: 100%;
 
-  // &__expand-icon {
-  //   position: absolute;
-  //   top: calc(50% - 6px);
-  //   right: 16px;
-  //   width: 10px;
-  //   transform-origin: none;
-  //   opacity: 0.45;
-
-  //   span[role='img'] {
-  //     margin-right: 0;
-  //     font-size: 11px;
-  //   }
-
-  //   &--collapsed {
-  //     opacity: 0;
-  //   }
-  // }
-
-  //  collapsed show title start
-  .@{basic-menu-content-prefix-cls}--show-title {
-    max-width: unset !important;
-    opacity: 1 !important;
-  }
-
-  &--hide-title {
-    &.ant-menu-inline-collapsed > .ant-menu-item,
-    &.ant-menu-inline-collapsed > .ant-menu-item-group > .ant-menu-item-group-list > .ant-menu-item,
-    &.ant-menu-inline-collapsed
-      > .ant-menu-item-group
-      > .ant-menu-item-group-list
-      > .ant-menu-submenu
-      > .ant-menu-submenu-title,
-    &.ant-menu-inline-collapsed .ant-menu-submenu-title {
-      padding-right: 16px !important;
-      padding-left: 16px !important;
-    }
-  }
-
-  &--collapsed-show-title.ant-menu-inline-collapsed {
-    .@{basic-menu-prefix-cls}-item__level1 {
-      padding: 2px 0;
-      justify-content: center !important;
-
-      &.ant-menu-item {
-        display: flex;
-        align-items: center;
-        height: 60px !important;
-        margin-top: 0 !important;
-        margin-bottom: 0 !important;
-        line-height: 60px !important;
-
-        > span {
-          margin-top: 10px;
-        }
-      }
-    }
-
-    & > li[role='menuitem']:not(.ant-menu-submenu),
-    & > li > .ant-menu-submenu-title {
-      display: flex;
-      margin-top: 10px;
-      font-size: 12px;
-      flex-direction: column;
-      align-items: center;
-      line-height: 24px;
-    }
-
-    & > li > .ant-menu-submenu-title {
-      line-height: 24px;
-    }
-    .@{basic-menu-content-prefix-cls}-wrapper {
-      display: flex;
-      justify-content: center;
-      align-items: center;
-      flex-direction: column;
-      .@{basic-menu-content-prefix-cls}--show-title {
-        line-height: 30px;
-      }
-    }
-  }
-
-  &.ant-menu-inline-collapsed > .ant-menu-item,
-  &.ant-menu-inline-collapsed > .ant-menu-item-group > .ant-menu-item-group-list > .ant-menu-item,
-  &.ant-menu-inline-collapsed
-    > .ant-menu-item-group
-    > .ant-menu-item-group-list
-    > .ant-menu-submenu
-    > .ant-menu-submenu-title,
-  &.ant-menu-inline-collapsed .ant-menu-submenu-title {
-    padding-right: 16px !important;
-    padding-left: 16px !important;
-  }
-
-  .@{basic-menu-content-prefix-cls}-wrapper {
-    width: 100%;
-    margin-top: 4px;
-
-    &__icon {
-      vertical-align: text-top;
-    }
-  }
-
   .ant-menu-item {
     transition: unset;
   }
@@ -179,117 +62,6 @@
     }
   }
 
-  &.ant-menu-dark:not(.@{basic-menu-prefix-cls}__sidebar-hor):not(.@{basic-menu-prefix-cls}__second) {
-    // Reset menu item row height
-    .ant-menu-item:not(.@{basic-menu-prefix-cls}-item__level1),
-    .ant-menu-sub.ant-menu-inline > .ant-menu-item,
-    .ant-menu-sub.ant-menu-inline > .ant-menu-submenu > .ant-menu-submenu-title {
-      height: @app-menu-item-height;
-      margin: 0;
-      line-height: @app-menu-item-height;
-    }
-
-    .ant-menu-item.@{basic-menu-prefix-cls}-item__level1 {
-      height: @app-menu-item-height;
-      line-height: @app-menu-item-height;
-    }
-  }
-
-  // 层级样式
-  &.ant-menu-dark:not(.@{basic-menu-prefix-cls}__sidebar-hor) {
-    overflow: hidden;
-    background: @sider-dark-bg-color;
-    .active-menu-style();
-
-    .ant-menu-item.ant-menu-item-selected.@{basic-menu-prefix-cls}-menu-item__level1,
-    .ant-menu-submenu-selected.@{basic-menu-prefix-cls}-menu-item__level1 {
-      color: @white;
-    }
-
-    .@{basic-menu-prefix-cls}-item__level1 {
-      background-color: @sider-dark-bg-color;
-
-      > .ant-menu-sub > li {
-        background-color: @sider-dark-lighten-1-bg-color;
-      }
-    }
-
-    .@{basic-menu-prefix-cls}-item__level2:not(.ant-menu-item-selected),
-    .ant-menu-sub {
-      background-color: @sider-dark-lighten-1-bg-color;
-    }
-
-    .@{basic-menu-prefix-cls}-item__level3:not(.ant-menu-item-selected) {
-      background-color: @sider-dark-lighten-2-bg-color;
-
-      .ant-menu-item {
-        background-color: @sider-dark-lighten-2-bg-color;
-      }
-    }
-
-    .ant-menu-submenu-title {
-      display: flex;
-      height: @app-menu-item-height;
-      // margin: 0;
-      align-items: center;
-    }
-
-    &.ant-menu-inline-collapsed {
-      .ant-menu-submenu-selected,
-      .ant-menu-item-selected {
-        position: relative;
-        font-weight: 500;
-        color: @white;
-        background: @sider-dark-darken-bg-color !important;
-
-        &::before {
-          position: absolute;
-          top: 0;
-          left: 0;
-          width: 3px;
-          height: 100%;
-          background: @primary-color;
-          content: '';
-        }
-      }
-    }
-  }
-
-  &.ant-menu-light:not(.@{basic-menu-prefix-cls}__sidebar-hor) {
-    // overflow: hidden;
-    border-right: none;
-
-    .ant-menu-item.ant-menu-item-selected.@{basic-menu-prefix-cls}-menu-item__level1,
-    .ant-menu-submenu-selected.@{basic-menu-prefix-cls}-menu-item__level1 {
-      color: @primary-color;
-    }
-  }
-
-  &.@{basic-menu-prefix-cls}__second.ant-menu-inline-collapsed:not(.@{basic-menu-prefix-cls}__sidebar-hor) {
-    // Reset menu item row height
-    .@{basic-menu-prefix-cls}-item__level1 {
-      display: flex;
-      height: @app-menu-item-height * 1.4;
-      padding: 6px 0 !important;
-      margin: 0;
-      font-size: 12px;
-      line-height: @app-menu-item-height;
-      align-items: center;
-      text-align: center;
-
-      > div {
-        padding: 6px 0 !important;
-        font-size: 12px;
-      }
-
-      .@{basic-menu-content-prefix-cls}__name {
-        display: inline-block;
-        width: 50%;
-        overflow: hidden;
-      }
-    }
-  }
-
   .ant-menu-submenu,
   .ant-menu-submenu-inline {
     transition: unset;
@@ -300,63 +72,3 @@
     transition: unset;
   }
 }
-
-.ant-menu-dark {
-  &.ant-menu-submenu-popup {
-    > ul {
-      background: @sider-dark-bg-color;
-    }
-    .active-menu-style();
-  }
-}
-
-// collapsed show title end
-.ant-menu-item,
-.ant-menu-submenu-title {
-  > .@{basic-menu-content-prefix-cls}__name {
-    width: 100%;
-
-    .@{basic-menu-tag-prefix-cls} {
-      float: right;
-      margin-top: @app-menu-item-height / 2;
-      transform: translate(0%, -50%);
-    }
-  }
-}
-
-.@{basic-menu-tag-prefix-cls} {
-  position: absolute;
-  top: calc(50% - 8px);
-  right: 30px;
-  display: inline-block;
-  padding: 2px 4px;
-  margin-right: 4px;
-  font-size: 12px;
-  line-height: 14px;
-  color: #fff;
-  border-radius: 2px;
-
-  &--dot {
-    top: calc(50% - 4px);
-    width: 6px;
-    height: 6px;
-    padding: 0;
-    border-radius: 50%;
-  }
-
-  &--primary {
-    background: @primary-color;
-  }
-
-  &--error {
-    background: @error-color;
-  }
-
-  &--success {
-    background: @success-color;
-  }
-
-  &--warn {
-    background: @warning-color;
-  }
-}

+ 0 - 3
src/layouts/default/menu/useLayoutMenu.ts

@@ -72,9 +72,6 @@ export function useSplitMenu(splitType: Ref<MenuSplitTyeEnum>) {
 
   // Handle left menu split
   async function handleSplitLeftMenu(parentPath: string) {
-    console.log('======================');
-    console.log(unref(getSplitLeft));
-    console.log('======================');
     if (unref(getSplitLeft) || unref(getIsMobile)) return;
 
     // spilt mode left

+ 4 - 3
src/layouts/page/ParentView.vue

@@ -19,9 +19,9 @@
           appear
         >
           <keep-alive v-if="openCache" :include="getCaches">
-            <component :is="Component" :key="route.fullPath" />
+            <component :is="Component" v-bind="getKey(Component, route)" />
           </keep-alive>
-          <component v-else :is="Component" :key="route.fullPath" />
+          <component v-else :is="Component" v-bind="getKey(Component, route)" />
         </transition>
       </template>
     </router-view>
@@ -34,7 +34,7 @@
   import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting';
 
   import { useTransitionSetting } from '/@/hooks/setting/useTransitionSetting';
-  import { useCache } from './useCache';
+  import { useCache, getKey } from './useCache';
   import { getTransitionName } from './transition';
 
   export default defineComponent({
@@ -56,6 +56,7 @@
         openCache,
         getEnableTransition,
         getTransitionName,
+        getKey,
       };
     },
   });

+ 1 - 8
src/layouts/page/index.vue

@@ -27,9 +27,6 @@
 </template>
 
 <script lang="ts">
-  import type { FunctionalComponent } from 'vue';
-  import type { RouteLocation } from 'vue-router';
-
   import { computed, defineComponent, unref } from 'vue';
 
   import FrameLayout from '/@/layouts/iframe/index.vue';
@@ -37,7 +34,7 @@
   import { useRootSetting } from '/@/hooks/setting/useRootSetting';
 
   import { useTransitionSetting } from '/@/hooks/setting/useTransitionSetting';
-  import { useCache } from './useCache';
+  import { useCache, getKey } from './useCache';
   import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting';
   import { getTransitionName } from './transition';
 
@@ -54,10 +51,6 @@
 
       const openCache = computed(() => unref(getOpenKeepAlive) && unref(getShowMultipleTab));
 
-      function getKey(component: FunctionalComponent & { type: Indexable }, route: RouteLocation) {
-        return !!component?.type.parentView ? {} : { key: route.fullPath };
-      }
-
       return {
         getTransitionName,
         openCache,

+ 7 - 0
src/layouts/page/useCache.ts

@@ -1,3 +1,5 @@
+import type { FunctionalComponent } from 'vue';
+import type { RouteLocation } from 'vue-router';
 import { computed, ref, unref } from 'vue';
 import { useRootSetting } from '/@/hooks/setting/useRootSetting';
 import { tryTsxEmit } from '/@/utils/helper/vueHelper';
@@ -6,6 +8,11 @@ import { tabStore, PAGE_LAYOUT_KEY } from '/@/store/modules/tab';
 import { useRouter } from 'vue-router';
 
 const ParentLayoutName = 'ParentLayout';
+
+export function getKey(component: FunctionalComponent & { type: Indexable }, route: RouteLocation) {
+  return !!component?.type.parentView ? {} : { key: route.fullPath };
+}
+
 export function useCache(isPage: boolean) {
   const name = ref('');
   const { currentRoute } = useRouter();

+ 4 - 4
yarn.lock

@@ -1768,10 +1768,10 @@
     "@vue/babel-plugin-jsx" "^1.0.1"
     hash-sum "^2.0.0"
 
-"@vitejs/plugin-vue@^1.1.2":
-  version "1.1.2"
-  resolved "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-1.1.2.tgz#64d1f0e0739675f5717015ffb4d861c53af8fe60"
-  integrity sha512-a5ORYuPsiAO4Kb2blA/x63mDiBQBxEJkbjhVtiv5IP/I7fGfpwXPPGHx9LHD4MedpXp8icngJYMKO0hOwahtmQ==
+"@vitejs/plugin-vue@1.1.0":
+  version "1.1.0"
+  resolved "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-1.1.0.tgz#8ae0b11388897b07259c9e5198c0e3fb5e4b37d9"
+  integrity sha512-ExlAt3nb3PB31jV9AgRZSMoGd+aQRU53fc/seghV8/l0JCzaX2mqlgpG8iytWkRxbBPgtAx4TpCPdiVKnTFT/A==
 
 "@vue/babel-helper-vue-transform-on@^1.0.2":
   version "1.0.2"