index.vue 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. <template>
  2. <div class="c-menu" :style="{ width: width }">
  3. <div class="header">XXS</div>
  4. <div class="contain">
  5. <!-- 一级菜单 -->
  6. <div
  7. class="m1"
  8. v-for="m1 in list"
  9. :key="m1.name"
  10. >
  11. <div @click="(e) => handleClick(e, 0, m1)">
  12. <div :class="{'row': true, 'row1': true, 'actLine': actLine(m1), 'active': row(m1)}">
  13. {{m1.title}}
  14. <RightOutlined class="open" v-if="icon(m1, 'down')" />
  15. <DownOutlined class="open" v-if="icon(m1, 'right')" />
  16. </div>
  17. <!-- 二级菜单 -->
  18. <div :class="{'item': true, 'active': children(m1)}">
  19. <div
  20. v-for="m2 in m1.children"
  21. :key="m2.name"
  22. >
  23. <div @click="(e) => handleClick(e, 1, m2)">
  24. <div :class="{'row': true, 'row2': true, 'active': row(m2)}">
  25. {{m2.title}}
  26. <RightOutlined class="open" v-if="icon(m2, 'down')" />
  27. <DownOutlined class="open" v-if="icon(m2, 'right')" />
  28. </div>
  29. <!-- 三级菜单 -->
  30. <div :class="{'item': true, 'active': children(m2)}">
  31. <div
  32. v-for="m3 in m2.children"
  33. :key="m3.name"
  34. >
  35. <div @click="(e) => handleClick(e, 2, m3)">
  36. <div :class="{'row': true, 'row3': true, 'active': row(m3)}">{{m3.title}}</div>
  37. </div>
  38. </div>
  39. </div>
  40. </div>
  41. </div>
  42. </div>
  43. </div>
  44. </div>
  45. </div>
  46. </div>
  47. </template>
  48. <script>
  49. import { defineComponent, ref, watch } from 'vue';
  50. import { useRouter } from 'vue-router';
  51. import { RightOutlined, DownOutlined } from '@ant-design/icons-vue';
  52. export default defineComponent({
  53. name: 'c-menu',
  54. components: {
  55. RightOutlined,
  56. DownOutlined
  57. },
  58. props:{
  59. width: { // 宽度
  60. type: String,
  61. default: '250px'
  62. },
  63. list: { // 菜单列表
  64. type: Array,
  65. default: []
  66. },
  67. active: { // 当前激活菜 例: edit
  68. type: String,
  69. default: ''
  70. },
  71. actives: { // 当前激活菜单链 例 setting-user-edit
  72. type: String,
  73. default: ''
  74. },
  75. change: { // 菜单变化的回调
  76. type: Function
  77. },
  78. },
  79. setup(props, { emit }) {
  80. const router = useRouter();
  81. const activeKeys = ref(props.actives || ''); // 当前激活菜单链
  82. const activeKey = ref(props.active || ''); // 当前激活菜单
  83. // icon激活状态
  84. const icon = (d, t) => {
  85. if(d.children && d.children.length) {
  86. let type = activeKeys.value.indexOf(d.name) >= 0 ? 'right' : 'down';
  87. return type === t
  88. } else {
  89. return false
  90. }
  91. };
  92. // 有子菜单的一级菜单。加一个竖线
  93. const actLine = (d) => {
  94. return activeKeys.value.indexOf(d.name) >= 0
  95. };
  96. // 子菜单菜单激活状态
  97. const children = (d) => {
  98. return d.children && d.children.length && (activeKeys.value.indexOf(d.name) >= 0)
  99. };
  100. // 菜单激活状态
  101. const row = (d) => {
  102. return activeKey.value === d.name
  103. };
  104. // 菜单点击
  105. const handleClick = (e, idx, d) => {
  106. e.stopPropagation();
  107. let arr = activeKeys.value.split('-');
  108. let flag = arr.some(item => item === d.name);
  109. // 已存在
  110. if(flag) {
  111. if(idx === 0) {
  112. arr = []
  113. } else if(idx === 1) {
  114. arr[1] = ''
  115. arr[2] = ''
  116. }
  117. } else {
  118. arr[idx] = d.name
  119. }
  120. activeKeys.value = arr.join('-')
  121. // 没有子菜单,需跳转页面
  122. if(!(d.children && d.children.length)) {
  123. activeKey.value = d.name
  124. router.push(d.path)
  125. emit('change', d)
  126. }
  127. };
  128. return {
  129. activeKeys,
  130. activeKey,
  131. icon,
  132. actLine,
  133. children,
  134. row,
  135. handleClick
  136. }
  137. }
  138. })
  139. </script>
  140. <style lang="less" scoped>
  141. .c-menu {
  142. height: 100vh;
  143. background-color: #4065e0;
  144. color: #fff;
  145. font-size: 16px;
  146. .header {
  147. font-size: 50px;
  148. text-align: center;
  149. line-height: 70px;
  150. }
  151. .contain {
  152. height: calc(100vh - 70px);
  153. overflow: auto;
  154. .row {
  155. padding: 14px 5px 14px 10px;
  156. cursor: pointer;
  157. position: relative;
  158. white-space: nowrap;
  159. text-overflow: ellipsis;
  160. overflow: hidden;
  161. word-break: break-all;
  162. .open {
  163. font-size: 13px;
  164. position: absolute;
  165. top: 20px;
  166. right: 10px;
  167. z-index: 9;
  168. }
  169. &:hover {
  170. /* color: @active; */
  171. background-color: #2546B1;
  172. }
  173. }
  174. .actLine {
  175. border-left: 2px solid #00f6f0;
  176. }
  177. .row2 {
  178. padding-left: 20px;
  179. }
  180. .row3 {
  181. padding-left: 30px;
  182. }
  183. .row.active {
  184. color: #00F6F0;
  185. background-color: #2546B1;
  186. }
  187. .item {
  188. height: 0px;
  189. overflow: hidden;
  190. }
  191. .item.active {
  192. height: auto;
  193. background-color: #2C4EBE;
  194. }
  195. }
  196. }
  197. </style>