Skip to content

Commit 92f149c

Browse files
committed
perf(QMenu,QTooltip): events handling on anchor
1 parent 16719db commit 92f149c

File tree

6 files changed

+75
-51
lines changed

6 files changed

+75
-51
lines changed

ui/dev/components/components/menu.vue

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,10 @@
5959
<q-btn color="primary" icon="map">
6060
<q-menu @show="log('@show popover_map')" @hide="log('@hide popover_map')">
6161
<q-list style="min-width: 100px">
62+
<div style="height: 50px" class="bg-grey-3">
63+
Weee
64+
</div>
65+
6266
<q-item
6367
v-for="n in 20"
6468
:key="n"

ui/src/components/menu/ClickOutside.js

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { listenOpts } from '../../utils/event.js'
2+
import { getVmOfNode, isVmChildOf } from '../../utils/vm.js'
23
import Platform from '../../plugins/Platform.js'
34

45
let timer
@@ -44,28 +45,20 @@ export default {
4445
handler (evt) {
4546
const target = evt.target
4647

47-
if (target === void 0 || target.nodeType === 8 || (ctx.toggleEl !== void 0 && ctx.toggleEl.contains(target))) {
48-
return
48+
if (
49+
target !== void 0 &&
50+
target.nodeType !== 8 &&
51+
(
52+
ctx.toggleEl === void 0 ||
53+
ctx.toggleEl.contains(target) === false
54+
) &&
55+
(
56+
target === document.body ||
57+
isVmChildOf(getVmOfNode(target), vmEl) === false
58+
)
59+
) {
60+
return ctx.trigger(evt)
4961
}
50-
51-
if (target !== document.body) {
52-
for (let node = target; node !== null; node = node.parentNode) {
53-
// node.__vue__ can be null if the instance was destroyed
54-
if (node.__vue__ === null) {
55-
return
56-
}
57-
if (node.__vue__ !== void 0) {
58-
for (let vm = node.__vue__; vm !== void 0; vm = vm.$parent) {
59-
if (vmEl === vm) {
60-
return
61-
}
62-
}
63-
break
64-
}
65-
}
66-
}
67-
68-
return ctx.trigger(evt)
6962
}
7063
}
7164

ui/src/components/menu/QMenu.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ export default Vue.extend({
242242
__renderPortal (h) {
243243
const on = {
244244
...this.$listeners,
245-
// stop propagating this events from children
245+
// stop propagating these events from children
246246
input: stop,
247247
'popup-show': stop,
248248
'popup-hide': stop

ui/src/components/tooltip/QTooltip.js

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import {
1212
validatePosition, validateOffset, setPosition, parsePosition
1313
} from '../../utils/position-engine.js'
1414

15+
const { passive } = listenOpts
16+
1517
export default Vue.extend({
1618
name: 'QTooltip',
1719

@@ -136,17 +138,17 @@ export default Vue.extend({
136138
__unconfigureAnchorEl () {
137139
// mobile hover ref https://stackoverflow.com/a/22444532
138140
if (this.$q.platform.is.mobile) {
139-
this.anchorEl.removeEventListener('touchstart', this.__delayShow, listenOpts.passive)
141+
this.anchorEl.removeEventListener('touchstart', this.__delayShow, passive)
140142
;['touchcancel', 'touchmove', 'click'].forEach(evt => {
141-
this.anchorEl.removeEventListener(evt, this.__delayHide, listenOpts.passive)
143+
this.anchorEl.removeEventListener(evt, this.__delayHide, passive)
142144
})
143145
}
144146
else {
145-
this.anchorEl.removeEventListener('mouseenter', this.__delayShow, listenOpts.passive)
147+
this.anchorEl.removeEventListener('mouseenter', this.__delayShow, passive)
146148
}
147149

148150
if (this.$q.platform.is.ios !== true) {
149-
this.anchorEl.removeEventListener('mouseleave', this.__delayHide, listenOpts.passive)
151+
this.anchorEl.removeEventListener('mouseleave', this.__delayHide, passive)
150152
}
151153
},
152154

@@ -155,24 +157,24 @@ export default Vue.extend({
155157

156158
// mobile hover ref https://stackoverflow.com/a/22444532
157159
if (this.$q.platform.is.mobile) {
158-
this.anchorEl.addEventListener('touchstart', this.__delayShow, listenOpts.passive)
160+
this.anchorEl.addEventListener('touchstart', this.__delayShow, passive)
159161
;['touchcancel', 'touchmove', 'click'].forEach(evt => {
160-
this.anchorEl.addEventListener(evt, this.__delayHide, listenOpts.passive)
162+
this.anchorEl.addEventListener(evt, this.__delayHide, passive)
161163
})
162164
}
163165
else {
164-
this.anchorEl.addEventListener('mouseenter', this.__delayShow, listenOpts.passive)
166+
this.anchorEl.addEventListener('mouseenter', this.__delayShow, passive)
165167
}
166168

167169
if (this.$q.platform.is.ios !== true) {
168-
this.anchorEl.addEventListener('mouseleave', this.__delayHide, listenOpts.passive)
170+
this.anchorEl.addEventListener('mouseleave', this.__delayHide, passive)
169171
}
170172
},
171173

172174
__unconfigureScrollTarget () {
173175
if (this.scrollTarget !== void 0) {
174-
this.scrollTarget.removeEventListener('scroll', this.updatePosition, listenOpts.passive)
175-
window.removeEventListener('scroll', this.updatePosition, listenOpts.passive)
176+
this.scrollTarget.removeEventListener('scroll', this.updatePosition, passive)
177+
window.removeEventListener('scroll', this.updatePosition, passive)
176178
this.scrollTarget = void 0
177179
}
178180
},
@@ -181,10 +183,10 @@ export default Vue.extend({
181183
if (this.anchorEl !== void 0) {
182184
this.scrollTarget = getScrollTarget(this.anchorEl)
183185
if (this.noParentEvent !== true) {
184-
this.scrollTarget.addEventListener('scroll', this.hide, listenOpts.passive)
186+
this.scrollTarget.addEventListener('scroll', this.hide, passive)
185187
}
186188
if (this.noParentEvent === true || this.scrollTarget !== window) {
187-
window.addEventListener('scroll', this.updatePosition, listenOpts.passive)
189+
window.addEventListener('scroll', this.updatePosition, passive)
188190
}
189191
}
190192
},

ui/src/mixins/anchor.js

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { clearSelection } from '../utils/selection.js'
2-
import { prevent } from '../utils/event.js'
2+
import { prevent, listenOpts } from '../utils/event.js'
3+
4+
const { passive, notPassive } = listenOpts
35

46
export default {
57
props: {
@@ -86,47 +88,46 @@ export default {
8688

8789
if (this.showing === true && evt !== void 0) {
8890
clearSelection()
89-
prevent(evt)
9091
}
9192
},
9293

9394
__unconfigureAnchorEl (context = this.contextMenu) {
9495
if (context === true) {
95-
if (this.$q.platform.is.mobile) {
96-
this.anchorEl.removeEventListener('touchstart', this.__mobileTouch)
96+
if (this.$q.platform.is.mobile === true) {
97+
this.anchorEl.removeEventListener('touchstart', this.__mobileTouch, passive)
9798
;['touchcancel', 'touchmove', 'touchend'].forEach(evt => {
98-
this.anchorEl.removeEventListener(evt, this.__mobileCleanup)
99+
this.anchorEl.removeEventListener(evt, this.__mobileCleanup, passive)
99100
})
100101
}
101102
else {
102-
this.anchorEl.removeEventListener('click', this.hide)
103-
this.anchorEl.removeEventListener('contextmenu', this.__contextClick)
103+
this.anchorEl.removeEventListener('click', this.hide, passive)
104+
this.anchorEl.removeEventListener('contextmenu', this.__contextClick, notPassive)
104105
}
105106
}
106107
else {
107-
this.anchorEl.removeEventListener('click', this.toggle)
108-
this.anchorEl.removeEventListener('keyup', this.__toggleKey)
108+
this.anchorEl.removeEventListener('click', this.toggle, passive)
109+
this.anchorEl.removeEventListener('keyup', this.__toggleKey, passive)
109110
}
110111
},
111112

112113
__configureAnchorEl (context = this.contextMenu) {
113114
if (this.noParentEvent === true) { return }
114115

115116
if (context === true) {
116-
if (this.$q.platform.is.mobile) {
117-
this.anchorEl.addEventListener('touchstart', this.__mobileTouch)
117+
if (this.$q.platform.is.mobile === true) {
118+
this.anchorEl.addEventListener('touchstart', this.__mobileTouch, passive)
118119
;['touchcancel', 'touchmove', 'touchend'].forEach(evt => {
119-
this.anchorEl.addEventListener(evt, this.__mobileCleanup)
120+
this.anchorEl.addEventListener(evt, this.__mobileCleanup, passive)
120121
})
121122
}
122123
else {
123-
this.anchorEl.addEventListener('click', this.hide)
124-
this.anchorEl.addEventListener('contextmenu', this.__contextClick)
124+
this.anchorEl.addEventListener('click', this.hide, passive)
125+
this.anchorEl.addEventListener('contextmenu', this.__contextClick, notPassive)
125126
}
126127
}
127128
else {
128-
this.anchorEl.addEventListener('click', this.toggle)
129-
this.anchorEl.addEventListener('keyup', this.__toggleKey)
129+
this.anchorEl.addEventListener('click', this.toggle, passive)
130+
this.anchorEl.addEventListener('keyup', this.__toggleKey, passive)
130131
}
131132
},
132133

@@ -160,7 +161,10 @@ export default {
160161
},
161162

162163
created () {
163-
if (typeof this.__configureScrollTarget === 'function' && typeof this.__unconfigureScrollTarget === 'function') {
164+
if (
165+
typeof this.__configureScrollTarget === 'function' &&
166+
typeof this.__unconfigureScrollTarget === 'function'
167+
) {
164168
this.noParentEventWatcher = this.$watch('noParentEvent', () => {
165169
if (this.scrollTarget !== void 0) {
166170
this.__unconfigureScrollTarget()

ui/src/utils/vm.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,24 @@ export function getAllChildren (vm, children = []) {
55
})
66
return children
77
}
8+
9+
export function getVmOfNode (el) {
10+
for (let node = el; node !== null; node = node.parentNode) {
11+
// node.__vue__ can be null if the instance was destroyed
12+
if (node.__vue__ === null) {
13+
return
14+
}
15+
if (node.__vue__ !== void 0) {
16+
return node.__vue__
17+
}
18+
}
19+
}
20+
21+
export function isVmChildOf (childVm, parentVm) {
22+
for (let vm = childVm; vm !== void 0; vm = vm.$parent) {
23+
if (vm === parentVm) {
24+
return true
25+
}
26+
}
27+
return false
28+
}

0 commit comments

Comments
 (0)