inleft
2024-05-18 2ddbd99aa5b2e396f96c6daba60fe1ac2573d9fb
commit | author | age
9bcb19 1 import Menu from 'ant-design-vue/es/menu'
I 2 import Icon from 'ant-design-vue/es/icon'
3
4 export default {
5   name: 'SMenu',
6   props: {
7     menu: {
8       type: Array,
9       required: true
10     },
11     theme: {
12       type: String,
13       required: false,
14       default: 'dark'
15     },
16     mode: {
17       type: String,
18       required: false,
19       default: 'inline'
20     },
21     collapsed: {
22       type: Boolean,
23       required: false,
24       default: false
25     }
26   },
27   data () {
28     return {
29       openKeys: [],
30       selectedKeys: [],
31       cachedOpenKeys: []
32     }
33   },
34   computed: {
35     rootSubmenuKeys: vm => {
36       const keys = []
37       vm.menu.forEach(item => keys.push(item.path))
38       return keys
39     }
40   },
41   mounted () {
42     this.updateMenu()
43   },
44   watch: {
45     collapsed (val) {
46       if (val) {
47         this.cachedOpenKeys = this.openKeys.concat()
48         this.openKeys = []
49       } else {
50         this.openKeys = this.cachedOpenKeys
51       }
52     },
53     $route: function () {
54       this.updateMenu()
55     }
56   },
57   methods: {
58     // select menu item
59     onOpenChange (openKeys) {
60       // 在水平模式下时执行,并且不再执行后续
61       if (this.mode === 'horizontal') {
62         this.openKeys = openKeys
63         return
64       }
65       // 非水平模式时
66       const latestOpenKey = openKeys.find(key => !this.openKeys.includes(key))
67       if (!this.rootSubmenuKeys.includes(latestOpenKey)) {
68         this.openKeys = openKeys
69       } else {
70         this.openKeys = latestOpenKey ? [latestOpenKey] : []
71       }
72     },
73     onSelect ({ item, key, selectedKeys }) {
74       this.selectedKeys = selectedKeys
75       this.$emit('select', { item, key, selectedKeys })
76     },
77     updateMenu () {
78       const routes = this.$route.matched.concat()
79       const { hidden } = this.$route.meta
80       if (routes.length >= 3 && hidden) {
81         routes.pop()
82         this.selectedKeys = [routes[routes.length - 1].path]
83       } else {
84         this.selectedKeys = [routes.pop().path]
85       }
86       const openKeys = []
87       if (this.mode === 'inline') {
88         routes.forEach(item => {
89           openKeys.push(item.path)
90         })
91       }
92
93       this.collapsed ? (this.cachedOpenKeys = openKeys) : (this.openKeys = openKeys)
94     },
95
96     // render
97     renderItem (menu) {
98       if (!menu.hidden) {
99         return menu.children && !menu.hideChildrenInMenu ? this.renderSubMenu(menu) : this.renderMenuItem(menu)
100       }
101       return null
102     },
103     renderMenuItem (menu) {
104       const target = menu.meta.target || null
105       const CustomTag = target && 'a' || 'router-link'
106       const props = { to: { name: menu.name } }
107       const attrs = { href: menu.path, target: menu.meta.target }
108
109       if (menu.children && menu.hideChildrenInMenu) {
110         // 把有子菜单的 并且 父菜单是要隐藏子菜单的
111         // 都给子菜单增加一个 hidden 属性
112         // 用来给刷新页面时, selectedKeys 做控制用
113         menu.children.forEach(item => {
114           item.meta = Object.assign(item.meta, { hidden: true })
115         })
116       }
117
118       return (
119         <Menu.Item {...{ key: menu.path }}>
120           <CustomTag {...{ props, attrs }}>
121             {this.renderIcon(menu.meta.icon)}
122             <span>{menu.meta.title}</span>
123           </CustomTag>
124         </Menu.Item>
125       )
126     },
127     renderSubMenu (menu) {
128       const itemArr = []
129       if (!menu.hideChildrenInMenu) {
130         menu.children.forEach(item => itemArr.push(this.renderItem(item)))
131       }
132       return (
133         <Menu.SubMenu {...{ key: menu.path }}>
134           <span slot="title">
135             {this.renderIcon(menu.meta.icon)}
136             <span>{menu.meta.title}</span>
137           </span>
138           {itemArr}
139         </Menu.SubMenu>
140       )
141     },
142     renderIcon (icon) {
143       if (icon === 'none' || icon === undefined) {
144         return null
145       }
146       const props = {}
147       typeof (icon) === 'object' ? props.component = icon : props.type = icon
148       return (
149         <Icon {... { props } }/>
150       )
151     }
152   },
153
154   render () {
155     const dynamicProps = {
156       props: {
157         mode: this.mode,
158         theme: this.theme,
159         openKeys: this.openKeys,
160         selectedKeys: this.selectedKeys
161       },
162       on: {
163         openChange: this.onOpenChange,
164         select: this.onSelect
165       }
166     }
167
168     const menuTree = this.menu.map(item => {
169       if (item.hidden) {
170         return null
171       }
172       return this.renderItem(item)
173     })
174
175     return (<Menu {...dynamicProps}>{menuTree}</Menu>)
176   }
177 }