提交 | 用户 | 时间
820397 1 <script lang="tsx">
H 2 import { PropType } from 'vue'
3 import { ElMenu, ElScrollbar } from 'element-plus'
4 import { useAppStore } from '@/store/modules/app'
5 import { usePermissionStore } from '@/store/modules/permission'
6 import { useRenderMenuItem } from './components/useRenderMenuItem'
7 import { isUrl } from '@/utils/is'
8 import { useDesign } from '@/hooks/web/useDesign'
9 import { LayoutType } from '@/types/layout'
10
11 const { getPrefixCls } = useDesign()
12
13 const prefixCls = getPrefixCls('menu')
14
15 export default defineComponent({
16   // eslint-disable-next-line vue/no-reserved-component-names
17   name: 'Menu',
18   props: {
19     menuSelect: {
20       type: Function as PropType<(index: string) => void>,
21       default: undefined
22     }
23   },
24   setup(props) {
25     const appStore = useAppStore()
26
27     const layout = computed(() => appStore.getLayout)
28
29     const { push, currentRoute } = useRouter()
30
31     const permissionStore = usePermissionStore()
32
33     const menuMode = computed((): 'vertical' | 'horizontal' => {
34       // 竖
35       const vertical: LayoutType[] = ['classic', 'topLeft', 'cutMenu']
36
37       if (vertical.includes(unref(layout))) {
38         return 'vertical'
39       } else {
40         return 'horizontal'
41       }
42     })
43
44     const routers = computed(() =>
45       unref(layout) === 'cutMenu' ? permissionStore.getMenuTabRouters : permissionStore.getRouters
46     )
47
48     const collapse = computed(() => appStore.getCollapse)
49
50     const uniqueOpened = computed(() => appStore.getUniqueOpened)
51
52     const activeMenu = computed(() => {
53       const { meta, path } = unref(currentRoute)
54       // if set path, the sidebar will highlight the path you set
55       if (meta.activeMenu) {
56         return meta.activeMenu as string
57       }
58       return path
59     })
60
61     const menuSelect = (index: string) => {
62       if (props.menuSelect) {
63         props.menuSelect(index)
64       }
65       // 自定义事件
66       if (isUrl(index)) {
67         window.open(index)
68       } else {
69         push(index)
70       }
71     }
72
73     const renderMenuWrap = () => {
74       if (unref(layout) === 'top') {
75         return renderMenu()
76       } else {
77         return <ElScrollbar>{renderMenu()}</ElScrollbar>
78       }
79     }
80
81     const renderMenu = () => {
82       return (
83         <ElMenu
84           defaultActive={unref(activeMenu)}
85           mode={unref(menuMode)}
86           collapse={
87             unref(layout) === 'top' || unref(layout) === 'cutMenu' ? false : unref(collapse)
88           }
89           uniqueOpened={unref(layout) === 'top' ? false : unref(uniqueOpened)}
90           backgroundColor="var(--left-menu-bg-color)"
91           textColor="var(--left-menu-text-color)"
92           activeTextColor="var(--left-menu-text-active-color)"
3e359e 93           popperClass={
H 94             unref(menuMode) === 'vertical'
95               ? `${prefixCls}-popper--vertical`
96               : `${prefixCls}-popper--horizontal`
97           }
820397 98           onSelect={menuSelect}
H 99         >
100           {{
101             default: () => {
102               const { renderMenuItem } = useRenderMenuItem(unref(menuMode))
103               return renderMenuItem(unref(routers))
104             }
105           }}
106         </ElMenu>
107       )
108     }
109
110     return () => (
111       <div
112         id={prefixCls}
113         class={[
114           `${prefixCls} ${prefixCls}__${unref(menuMode)}`,
115           'h-[100%] overflow-hidden flex-col bg-[var(--left-menu-bg-color)]',
116           {
117             'w-[var(--left-menu-min-width)]': unref(collapse) && unref(layout) !== 'cutMenu',
118             'w-[var(--left-menu-max-width)]': !unref(collapse) && unref(layout) !== 'cutMenu'
119           }
120         ]}
121       >
122         {renderMenuWrap()}
123       </div>
124     )
125   }
126 })
127 </script>
128
129 <style lang="scss" scoped>
130 $prefix-cls: #{$namespace}-menu;
131
132 .#{$prefix-cls} {
133   position: relative;
134   transition: width var(--transition-time-02);
135
136   :deep(.#{$elNamespace}-menu) {
137     width: 100% !important;
138     border-right: none;
139
140     // 设置选中时子标题的颜色
141     .is-active {
142       & > .#{$elNamespace}-sub-menu__title {
143         color: var(--left-menu-text-active-color) !important;
144       }
145     }
146
147     // 设置子菜单悬停的高亮和背景色
148     .#{$elNamespace}-sub-menu__title,
149     .#{$elNamespace}-menu-item {
150       &:hover {
151         color: var(--left-menu-text-active-color) !important;
152         background-color: var(--left-menu-bg-color) !important;
153       }
154     }
155
156     // 设置选中时的高亮背景和高亮颜色
157     .#{$elNamespace}-menu-item.is-active {
158       color: var(--left-menu-text-active-color) !important;
159       background-color: var(--left-menu-bg-active-color) !important;
160
161       &:hover {
162         background-color: var(--left-menu-bg-active-color) !important;
163       }
164     }
165
166     .#{$elNamespace}-menu-item.is-active {
167       position: relative;
168     }
169
170     // 设置子菜单的背景颜色
171     .#{$elNamespace}-menu {
172       .#{$elNamespace}-sub-menu__title,
173       .#{$elNamespace}-menu-item:not(.is-active) {
174         background-color: var(--left-menu-bg-light-color) !important;
175       }
176     }
177   }
178
179   // 折叠时的最小宽度
180   :deep(.#{$elNamespace}-menu--collapse) {
181     width: var(--left-menu-min-width);
182
183     & > .is-active,
184     & > .is-active > .#{$elNamespace}-sub-menu__title {
185       position: relative;
186       background-color: var(--left-menu-collapse-bg-active-color) !important;
187     }
188   }
189
190   // 折叠动画的时候,就需要把文字给隐藏掉
191   :deep(.horizontal-collapse-transition) {
192     // transition: 0s width ease-in-out, 0s padding-left ease-in-out, 0s padding-right ease-in-out !important;
193     .#{$prefix-cls}__title {
194       display: none;
195     }
196   }
197
3e359e 198   // 垂直菜单
H 199   &__vertical {
200     :deep(.#{$elNamespace}-menu--vertical) {
201       &:not(.#{$elNamespace}-menu--collapse) .#{$elNamespace}-sub-menu__title,
202       .#{$elNamespace}-menu-item {
203         padding-right: 0;
204       }
205     }
206   }
207
820397 208   // 水平菜单
H 209   &__horizontal {
210     height: calc(var(--top-tool-height)) !important;
211
212     :deep(.#{$elNamespace}-menu--horizontal) {
213       height: calc(var(--top-tool-height));
214       border-bottom: none;
215       // 重新设置底部高亮颜色
216       & > .#{$elNamespace}-sub-menu.is-active {
217         .#{$elNamespace}-sub-menu__title {
218           border-bottom-color: var(--el-color-primary) !important;
219         }
220       }
221
222       .#{$elNamespace}-menu-item.is-active {
223         position: relative;
224
225         &::after {
226           display: none !important;
227         }
228       }
229
230       .#{$prefix-cls}__title {
231         /* stylelint-disable-next-line */
232         max-height: calc(var(--top-tool-height) - 2px) !important;
233         /* stylelint-disable-next-line */
234         line-height: calc(var(--top-tool-height) - 2px);
235       }
236     }
237   }
238 }
239 </style>
240
241 <style lang="scss">
242 $prefix-cls: #{$namespace}-menu-popper;
243
244 .#{$prefix-cls}--vertical,
245 .#{$prefix-cls}--horizontal {
246   // 设置选中时子标题的颜色
247   .is-active {
248     & > .el-sub-menu__title {
249       color: var(--left-menu-text-active-color) !important;
250     }
251   }
252
253   // 设置子菜单悬停的高亮和背景色
254   .el-sub-menu__title,
255   .el-menu-item {
256     &:hover {
257       color: var(--left-menu-text-active-color) !important;
258       background-color: var(--left-menu-bg-color) !important;
259     }
260   }
261
262   // 设置选中时的高亮背景
263   .el-menu-item.is-active {
264     position: relative;
265     background-color: var(--left-menu-bg-active-color) !important;
266
267     &:hover {
268       background-color: var(--left-menu-bg-active-color) !important;
269     }
270   }
271 }
272 </style>