f7da272844226445f49461682a7a172633a80e1e.svn-base 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. import Menu from 'ant-design-vue/es/menu'
  2. import Icon from 'ant-design-vue/es/icon'
  3. const { Item, SubMenu } = Menu
  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. updateMenu () {
  74. const routes = this.$route.matched.concat()
  75. const { hidden } = this.$route.meta
  76. if (routes.length >= 3 && hidden) {
  77. routes.pop()
  78. this.selectedKeys = [routes[routes.length - 1].path]
  79. } else {
  80. this.selectedKeys = [routes.pop().path]
  81. }
  82. let openKeys = []
  83. if (this.mode === 'inline') {
  84. routes.forEach(item => {
  85. openKeys.push(item.path)
  86. })
  87. }
  88. // update-begin-author:sunjianlei date:20210409 for: 修复动态功能测试菜单、带参数菜单标题错误、展开错误的问题
  89. // 包含冒号的是动态菜单
  90. if (this.selectedKeys[0].includes(':')) {
  91. let selectedKey = this.$route.fullPath
  92. this.selectedKeys = [selectedKey]
  93. let newOpenKeys = []
  94. this.fullOpenKeys(this.menu, selectedKey, newOpenKeys)
  95. if (newOpenKeys.length > 0) {
  96. openKeys = newOpenKeys.reverse()
  97. }
  98. }
  99. // update-end-author:sunjianlei date:20210409 for: 修复动态功能测试菜单、带参数菜单标题错误、展开错误的问题
  100. //update-begin-author:taoyan date:20190510 for:online表单菜单点击展开的一级目录不对
  101. if(!this.selectedKeys || this.selectedKeys[0].indexOf(":")<0){
  102. this.collapsed ? (this.cachedOpenKeys = openKeys) : (this.openKeys = openKeys)
  103. }
  104. //update-end-author:taoyan date:20190510 for:online表单菜单点击展开的一级目录不对
  105. },
  106. // update-begin-author:sunjianlei date:20210409 for: 修复动态功能测试菜单、带参数菜单标题错误、展开错误的问题
  107. // 递归查找当前选中的菜单和父级菜单,填充openKeys
  108. fullOpenKeys(menus, selectedKey, openKeys) {
  109. for (let item of menus) {
  110. if (item.path === selectedKey) {
  111. openKeys.push(item.path)
  112. this.$emit('updateMenuTitle', item)
  113. return true
  114. } else if (Array.isArray(item.children)) {
  115. if (this.fullOpenKeys(item.children, selectedKey, openKeys)) {
  116. openKeys.push(item.path)
  117. return true
  118. }
  119. }
  120. }
  121. },
  122. // update-end-author:sunjianlei date:20210409 for: 修复动态功能测试菜单、带参数菜单标题错误、展开错误的问题
  123. // render
  124. renderItem (menu) {
  125. if (!menu.hidden) {
  126. return menu.children && !menu.alwaysShow ? this.renderSubMenu(menu) : this.renderMenuItem(menu)
  127. }
  128. return null
  129. },
  130. renderMenuItem (menu) {
  131. const target = menu.meta.target || null
  132. const tag = target && 'a' || 'router-link'
  133. let props = { to: { name: menu.name } }
  134. if(menu.route && menu.route === '0'){
  135. props = { to: { path: menu.path } }
  136. }
  137. const attrs = { href: menu.path, target: menu.meta.target }
  138. if (menu.children && menu.alwaysShow) {
  139. // 把有子菜单的 并且 父菜单是要隐藏子菜单的
  140. // 都给子菜单增加一个 hidden 属性
  141. // 用来给刷新页面时, selectedKeys 做控制用
  142. menu.children.forEach(item => {
  143. item.meta = Object.assign(item.meta, { hidden: true })
  144. })
  145. }
  146. return (
  147. <Item {...{ key: menu.path }}>
  148. <tag {...{ props, attrs }}>
  149. {this.renderIcon(menu.meta.icon)}
  150. <span>{menu.meta.title}</span>
  151. </tag>
  152. </Item>
  153. )
  154. },
  155. renderSubMenu (menu) {
  156. const itemArr = []
  157. if (!menu.alwaysShow) {
  158. menu.children.forEach(item => itemArr.push(this.renderItem(item)))
  159. }
  160. return (
  161. <SubMenu {...{ key: menu.path }}>
  162. <span slot="title">
  163. {this.renderIcon(menu.meta.icon)}
  164. <span>{menu.meta.title}</span>
  165. </span>
  166. {itemArr}
  167. </SubMenu>
  168. )
  169. },
  170. renderIcon (icon) {
  171. if (icon === 'none' || icon === undefined) {
  172. return null
  173. }
  174. const props = {}
  175. typeof (icon) === 'object' ? props.component = icon : props.type = icon
  176. return (
  177. <Icon {... { props } }/>
  178. )
  179. }
  180. },
  181. render () {
  182. const { mode, theme, menu } = this
  183. const props = {
  184. mode: mode,
  185. theme: theme,
  186. openKeys: this.openKeys
  187. }
  188. const on = {
  189. select: obj => {
  190. this.selectedKeys = obj.selectedKeys
  191. this.$emit('select', obj)
  192. },
  193. openChange: this.onOpenChange
  194. }
  195. const menuTree = menu.map(item => {
  196. if (item.hidden) {
  197. return null
  198. }
  199. return this.renderItem(item)
  200. })
  201. // {...{ props, on: on }}
  202. return (
  203. <Menu vModel={this.selectedKeys} {...{ props, on: on }}>
  204. {menuTree}
  205. </Menu>
  206. )
  207. }
  208. }