7
7
<div
8
8
class =" w-full h-full relative mx-auto border-solid border-0 border-t-4 border-b-4"
9
9
:class =" {
10
- 'border-transparent': !hoveredSection ,
11
- 'border-editor-primary': hoveredSection ,
10
+ 'border-transparent': !mustBeDisplayed ,
11
+ 'border-editor-primary': mustBeDisplayed ,
12
12
}"
13
13
>
14
14
<transition
15
15
name =" slide-fade"
16
16
mode =" out-in"
17
- v-on:after-leave =" afterAnimationDone"
18
17
>
19
18
<top-left-actions
20
19
:hovered-section =" hoveredSection"
21
- v-if =" hoveredSection "
20
+ v-if =" mustBeDisplayed "
22
21
/>
23
22
</transition >
24
23
25
24
<transition name =" reverse-slide-fade" mode =" out-in" >
26
25
<top-right-actions
27
26
:hoveredSection =" hoveredSection"
28
- v-if =" hoveredSection "
27
+ v-if =" mustBeDisplayed "
29
28
/>
30
29
</transition >
31
30
32
31
<transition name =" slide-up-fade" mode =" out-in" >
33
32
<bottom-actions
34
33
:hovered-section =" hoveredSection"
35
- v-if =" hoveredSection "
34
+ v-if =" mustBeDisplayed "
36
35
/>
37
36
</transition >
38
37
</div >
@@ -44,6 +43,7 @@ import TransformationMixin from '@/mixins/preview-transformation'
44
43
import TopLeftActions from ' ./top-left-actions.vue'
45
44
import TopRightActions from ' ./top-right-actions.vue'
46
45
import BottomActions from ' ./bottom-actions.vue'
46
+ import { debounce } from ' @/misc/utils'
47
47
48
48
export default {
49
49
name: ' SectionHighlighter' ,
@@ -53,11 +53,11 @@ export default {
53
53
hoveredSection: { type: Object },
54
54
},
55
55
data () {
56
- return { shadow : null , style : {} }
56
+ return { style : {}, isScrolling : false , boundingRect : null }
57
57
},
58
58
mounted () {
59
- // NOTE: optimized version to update the highlighter when scrolling the iframe
60
59
window .addEventListener (' maglev:preview:scroll' , this .onPreviewScroll )
60
+ this .waitUntilScrollingDone = debounce (this .onEndPreviewScrolling .bind (this ), 800 )
61
61
},
62
62
beforeDestroy () {
63
63
window .removeEventListener (' maglev:preview:scroll' , this .onPreviewScroll )
@@ -66,21 +66,28 @@ export default {
66
66
minTop () {
67
67
return this .hoveredSection ? .sectionOffsetTop || 0
68
68
},
69
+ mustBeDisplayed () {
70
+ return !! this .hoveredSection && ! this .isScrolling
71
+ }
69
72
},
70
73
methods: {
71
- afterAnimationDone () {
72
- this .shadow = null
74
+ onPreviewScroll (event ) {
75
+ this .isScrolling = true
76
+ this .boundingRect = event .detail .boundingRect
77
+ this .waitUntilScrollingDone ()
73
78
},
74
- onPreviewScroll (event ) {
75
- let self = this
76
- window .requestAnimationFrame (() => {
77
- const newStyle = this .performStyle (event .detail .boundingRect )
78
- Object .entries (newStyle).forEach (
79
- ([key , value ]) => (self .$el .style [key] = value),
80
- )
81
- })
79
+ onEndPreviewScrolling () {
80
+ this .isScrolling = false
81
+ this .applyStyle (this .boundingRect )
82
82
},
83
- performStyle (boundingRect ) {
83
+ applyStyle (boundingRect ) {
84
+ const self = this
85
+ const newStyle = this .calculateStyle (boundingRect)
86
+ Object .entries (newStyle).forEach (
87
+ ([key , value ]) => (self .$el .style [key] = value),
88
+ )
89
+ },
90
+ calculateStyle (boundingRect ) {
84
91
const isSticky = boundingRect .top < this .minTop
85
92
const top = isSticky ? this .minTop : boundingRect .top
86
93
const height = isSticky
@@ -102,17 +109,16 @@ export default {
102
109
},
103
110
},
104
111
watch: {
105
- hoveredSection (value , oldValue ) {
106
- if (! value) this .shadow = { ... oldValue }
107
-
108
- if (! this .hoveredSection && ! this .shadow ) {
109
- this .style = {}
110
- return
111
- }
112
+ hoveredSection: {
113
+ handler (value ) {
114
+ if (! value) return
112
115
113
- const { sectionRect } = value || this .shadow
114
- this .style = this .performStyle (sectionRect)
115
- },
116
+ this .isScrolling = false
117
+ this .boundingRect = value .sectionRect
118
+ this .applyStyle (value .sectionRect )
119
+ },
120
+ immediate: true
121
+ }
116
122
},
117
123
}
118
124
< / script>
0 commit comments