uni-nav-menu.vue 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. <template>
  2. <view class="uni-nav-menu" :style="{'background-color':backgroundColor}">
  3. <slot>
  4. <uni-menu-sidebar :data="data"></uni-menu-sidebar>
  5. </slot>
  6. </view>
  7. </template>
  8. <script>
  9. export default {
  10. name: 'uniNavMenu',
  11. props: {
  12. data: {
  13. type: Array,
  14. default () {
  15. return []
  16. }
  17. },
  18. // 模式 可选值 horizontal / vertical
  19. mode: {
  20. type: String,
  21. default: 'vertical'
  22. },
  23. // 是否水平折叠收起菜单(仅在 mode 为 vertical 时可用)
  24. collapse: {
  25. type: Boolean,
  26. default: false
  27. },
  28. // 菜单的背景色
  29. backgroundColor: {
  30. type: String,
  31. default: '#fff'
  32. },
  33. // 菜单的文字颜色
  34. textColor: {
  35. type: String,
  36. default: '#303133'
  37. },
  38. // 当前激活菜单的文字颜色
  39. activeTextColor: {
  40. type: String,
  41. default: '#42B983'
  42. },
  43. // 当前激活菜单的背景色
  44. activeBackgroundColor: {
  45. type: String,
  46. default: 'inherit'
  47. },
  48. // 如果 index 为 Object ,需要指定选中字段的名称
  49. activeKey: {
  50. type: String,
  51. default: 'id'
  52. },
  53. // 当前激活菜单的 index
  54. active: {
  55. type: String,
  56. default: ''
  57. },
  58. // 当前打开的 sub-menu 的 index 的数组
  59. defaultOpeneds: {
  60. type: Array,
  61. default () {
  62. return []
  63. }
  64. },
  65. // 是否只保持一个子菜单的展开
  66. uniqueOpened: {
  67. type: Boolean,
  68. default: false
  69. },
  70. // TODO 子菜单打开的触发方式(只在 mode 为 horizontal 时有效) ,可选值 hover / click
  71. menuTrigger: {
  72. type: String,
  73. default: 'hover'
  74. },
  75. router: {
  76. type: Boolean,
  77. default: false
  78. },
  79. // 是否开启折叠动画
  80. collapseTransition: {
  81. type: Boolean,
  82. default: true
  83. }
  84. },
  85. data() {
  86. return {
  87. activeIndex: this.active
  88. };
  89. },
  90. watch: {
  91. active(newVal) {
  92. this.activeIndex=newVal
  93. },
  94. activeIndex(newVal, oldVal) {
  95. if (this.itemChildrens.length > 0) {
  96. let isActive = false
  97. for(let i = 0 ; i < this.itemChildrens.length ;i++){
  98. const item = this.itemChildrens[i]
  99. isActive = this.isActive(item)
  100. if(isActive) break
  101. }
  102. if(!isActive){
  103. this.closeAll()
  104. }
  105. }
  106. }
  107. },
  108. created() {
  109. this.itemChildrens = []
  110. this.subChildrens = []
  111. // this.activeIndex = this.active
  112. },
  113. methods: {
  114. // menu 菜单激活回调
  115. select(key, keyPath) {
  116. this.$emit('select', key, keyPath)
  117. },
  118. // sub-menu 展开的回调
  119. open(key, keyPath) {
  120. this.$emit('open', key, keyPath)
  121. },
  122. // sub-menu 收起的回调
  123. close(key, keyPath) {
  124. this.$emit('close', key, keyPath)
  125. },
  126. // 判断当前选中,只有初始值会使用
  127. isActive(subItem) {
  128. let active = ''
  129. let isActive = false
  130. if(typeof(subItem.index) === 'object'){
  131. active = subItem.index[this.activeKey] || ''
  132. }else{
  133. active = subItem.index
  134. }
  135. if (subItem.index && this.activeIndex === active) {
  136. isActive = true
  137. subItem.$subMenu.forEach((item, index) => {
  138. if (!item.disabled && !subItem.disabled ) {
  139. subItem.indexPath.push(item.index)
  140. item.isOpen = true
  141. }
  142. })
  143. if(!subItem.active){
  144. subItem.onClickItem('init')
  145. }
  146. }
  147. return isActive
  148. },
  149. // 打开关闭 sunMenu
  150. selectMenu(subMenu){
  151. // const subMenu = this.$menuParent
  152. this.subChildrens.forEach((item,index)=>{
  153. if(item === subMenu){
  154. subMenu.isOpen = !subMenu.isOpen
  155. subMenu.indexPath.push(subMenu.index)
  156. }else{
  157. if(item.isOpen && this.uniqueOpened) item.isOpen = false
  158. }
  159. })
  160. subMenu.$subMenu.forEach((sub,idx)=>{
  161. sub.isOpen = true
  162. subMenu.indexPath.unshift(sub.index)
  163. })
  164. if(subMenu.isOpen){
  165. this.open(subMenu.indexPath[subMenu.indexPath.length-1],subMenu.indexPath)
  166. }else{
  167. this.close(subMenu.indexPath[subMenu.indexPath.length-1],subMenu.indexPath)
  168. }
  169. subMenu.indexPath = []
  170. },
  171. // 关闭其他选中
  172. closeOtherActive(itemMenu) {
  173. // let parents = this.$menuParent
  174. itemMenu.indexPath = []
  175. itemMenu.$subMenu.forEach((item) => {
  176. if (!item.disabled) {
  177. itemMenu.indexPath.push(item.index)
  178. }
  179. })
  180. this.itemChildrens.map((item) => {
  181. if (item.active) {
  182. item.active = false
  183. }
  184. return item
  185. })
  186. },
  187. // 关闭所有
  188. closeAll() {
  189. this.subChildrens.forEach((item) => {
  190. if (item.isOpen) {
  191. item.isOpen = false
  192. }
  193. })
  194. }
  195. }
  196. }
  197. </script>
  198. <style lang="scss">
  199. .uni-nav-menu {
  200. width: 240px;
  201. // min-height: 500px;
  202. background-color: #FFFFFF;
  203. font-size: 14px;
  204. }
  205. </style>