Menu组件
1 <template>
2 <div class="menu" v-if="global.v > 0">
3 <div>v:{{ global.v }} level:{{ global.level }}</div>
4 <ul @mouseenter="enter()" @mouseleave="leave()">
5 <li v-for="menu in menus" :key="menu.id" @mouseenter="active(menu)" :class="{ active: level <= global.level && activeMenuId == menu.id }">{{ menu.id }}_L{{ level }}</li>
6 </ul>
7 <div v-if="submenu && this.level - this.global.level < 1" class="menu-sub">
8 <A :global="global" :level="level + 1" :menus="submenu"></A>
9 </div>
10 </div>
11 </template>
12
13 <script>
14 export default {
15 name: 'A',
16 props: {
17 global: {
18 type: Object,
19 default: () => {
20 return { v: 0, level: 1 }
21 }
22 },
23 level: {},
24 menus: {}
25 },
26 components: {},
27 data() {
28 return {
29 submenu: null,
30 activeMenuId: null
31 }
32 },
33 created() {},
34 methods: {
35 active(menu) {
36 this.activeMenuId = menu.id
37 this.delay(() => {
38 this.submenu = menu.submenu
39 console.info('show_sub_menu')
40 })
41 },
42 enter() {
43 this.global.level = this.level
44 },
45 leave() {
46 this.delay(() => {
47 if (this.level == this.global.level) this.global.level--
48 })
49 },
50 showSub() {
51 return this.submenu && this.level - this.global.level > 0
52 },
53 delay(cb, delay) {
54 let v = ++this.global.v
55 setTimeout(() => {
56 if (this.global.v === v) {
57 cb()
58 }
59 }, delay || 50)
60 },
61 hide() {
62 this.global.v = 0
63 },
64 show() {
65 this.global.v = 1
66 }
67 }
68 }
69 </script>
70
71 <style>
72 .menu {
73 display: inline-block;
74 position: relative;
75 border: solid 1px #abc;
76 padding: 0px;
77 min-width: 100px;
78 background-color: beige;
79 }
80
81 .menu ul {
82 padding: 0;
83 margin: 0;
84 }
85
86 .menu .menu-sub {
87 position: absolute;
88 top: 0;
89 left: 100%;
90 }
91
92 .menu ul li {
93 list-style: none;
94 margin: 2px;
95 padding: 2px 10px;
96 }
97
98 .menu .active {
99 background-color: rgb(183, 218, 250);
100 }
101 </style>
使用
1 <template>
2 <div class="hello">
3 <div><button @click="showMenu">File</button></div>
4 <A :level="1" :menus="menus" ref="GMenu"></A>
5 </div>
6 </template>
7
8 <script>
9 import A from './A'
10
11 let menus = [
12 {
13 id: 'a',
14 submenu: [
15 {
16 id: 'aa',
17 submenu: [{ id: 'aaa' }, { id: 'aab' }, { id: 'aac' }]
18 },
19 { id: 'ab' },
20 { id: 'ac' }
21 ]
22 }
23 ]
24
25 let makeMenu = (menus, pid, deep) => {
26 let m = Math.floor(Math.random() * 10) + 9
27 for (let index = 0; index < m; index++) {
28 let menu = { id: pid + '' + index }
29 let submenu = []
30 if (deep < 3) {
31 menu.submenu = makeMenu(submenu, menu.id, deep + 1)
32 }
33 menus.push(menu)
34 }
35 return menus
36 }
37
38 makeMenu(menus, 'm', 1)
39
40 console.info(menus)
41
42 export default {
43 components: { A },
44 name: 'HelloWorld',
45 data() {
46 return {
47 menus: menus
48 }
49 },
50 props: {
51 msg: String
52 },
53 created() {
54 let self = this
55 document.getElementsByTagName('body')[0].addEventListener('click', (e) => {
56 e.stopPropagation()
57 e.preventDefault()
58 if (e.target.tagName === 'BODY') {
59 console.log(e)
60 self.hideMenu()
61 }
62 })
63 },
64 methods: {
65 showMenu() {
66 this.$refs.GMenu.show()
67 },
68 hideMenu() {
69 this.$refs.GMenu.hide()
70 }
71 }
72 }
73 </script>
74
75 <!-- Add "scoped" attribute to limit CSS to this component only -->
76 <style scoped>
77 h3 {
78 margin: 40px 0 0;
79 }
80 ul {
81 list-style-type: none;
82 padding: 0;
83 }
84 li {
85 display: inline-block;
86 margin: 0 10px;
87 }
88 a {
89 color: #42b983;
90 }
91 </style>