1
1
<template >
2
2
<div
3
3
ref =" stateEl"
4
- class =" absolute top-0 left-0 right-0 bottom-0 cursor-pointer opacity-0 hover:opacity-[8%] focus:opacity-[12%] active:opacity-[12%]"
5
- :class =" { 'pointer-events-none': disabled }"
4
+ class =" mv- absolute mv- top-0 mv- left-0 mv- right-0 mv- bottom-0 mv- cursor-pointer mv- opacity-0 sm: hover:mv- opacity-[8%] sm: focus:mv- opacity-[12%] sm: active:mv- opacity-[12%]"
5
+ :class =" [classes, { 'mv- pointer-events-none': disabled }] "
6
6
:style =" `${background}`"
7
+ @click.stop
7
8
/>
8
9
<span
10
+ v-show =" rippled"
9
11
ref =" rippleEl"
10
- class =" ripple opacity-0 absolute pointer-events-none"
12
+ class =" ripple mv- opacity-0 mv- absolute mv- pointer-events-none"
11
13
:style =" `
12
14
background: radial-gradient(
13
15
closest-side,
@@ -36,8 +38,18 @@ const props = defineProps({
36
38
type: String ,
37
39
default: null ,
38
40
},
41
+ rippled: {
42
+ type: Boolean ,
43
+ default: true ,
44
+ },
45
+ classes: {
46
+ type: String ,
47
+ default: null ,
48
+ },
39
49
})
40
50
51
+ const emits = defineEmits ([' click' ])
52
+
41
53
const stateEl = ref (null )
42
54
const rippleEl = ref (null )
43
55
const rectWidth = ref (null )
@@ -73,6 +85,7 @@ function getEndPoint() {
73
85
let animation = null
74
86
75
87
function handleTouchStart(event) {
88
+ shouldEmit.value = true
76
89
showRipple.value = true
77
90
ripplePos.value.x = event.offsetX
78
91
ripplePos.value.y = event.offsetY
@@ -101,6 +114,8 @@ function handleTouchStart(event) {
101
114
)
102
115
}
103
116
async function handleTouchEnd() {
117
+ if (showRipple.value === false) return
118
+
104
119
let pressAnimationPlayState = Infinity
105
120
if (typeof animation?.currentTime === 'number') {
106
121
pressAnimationPlayState = animation.currentTime
@@ -120,7 +135,15 @@ async function handleTouchEnd() {
120
135
animEnd()
121
136
}
122
137
123
- function animEnd() {
138
+ const shouldEmit = ref(true)
139
+
140
+ function handleTouchLeave() {
141
+ if (showRipple.value === false) return
142
+ shouldEmit.value = false
143
+ animEnd()
144
+ }
145
+
146
+ async function animEnd() {
124
147
showRipple.value = false
125
148
126
149
rippleEl.value.animate(
@@ -133,15 +156,25 @@ function animEnd() {
133
156
easing: EASING.STANDARD_ACCELERATE,
134
157
}
135
158
)
159
+
160
+ if (!shouldEmit.value) return
161
+
162
+ await new Promise((resolve) => {
163
+ setTimeout(resolve, 30)
164
+ })
165
+
166
+ emits('click')
167
+ shouldEmit.value = false
136
168
}
137
169
138
170
let rippleScale = null
139
171
let initialSize = null
140
172
141
173
onMounted(() => {
142
- stateEl.value.addEventListener('mousedown', handleTouchStart)
143
- stateEl.value.addEventListener('mouseup', handleTouchEnd)
144
- stateEl.value.addEventListener('mouseleave', handleTouchEnd)
174
+ stateEl.value.addEventListener('pointerdown', handleTouchStart)
175
+ stateEl.value.addEventListener('pointerup', handleTouchEnd)
176
+ stateEl.value.addEventListener('contextmenu', handleTouchLeave)
177
+ stateEl.value.addEventListener('pointerleave', handleTouchLeave)
145
178
146
179
const { height, width } = stateEl.value.getBoundingClientRect()
147
180
const maxDim = Math.max(height, width)
@@ -160,15 +193,16 @@ onMounted(() => {
160
193
161
194
onUnmounted(() => {
162
195
if (stateEl.value) {
163
- stateEl.value.removeEventListener('mousedown', handleTouchStart)
164
- stateEl.value.removeEventListener('mouseup', handleTouchEnd)
165
- stateEl.value.removeEventListener('mouseleave', handleTouchEnd)
196
+ stateEl.value.removeEventListener('pointerdown', handleTouchStart)
197
+ stateEl.value.removeEventListener('pointerup', handleTouchEnd)
198
+ stateEl.value.removeEventListener('contextmenu', handleTouchLeave)
199
+ stateEl.value.removeEventListener('pointerleave', handleTouchLeave)
166
200
}
167
201
})
168
202
</script>
169
203
170
204
<script>
171
205
export default {
172
- name: 'MVStateLayer ',
206
+ name: 'MStateLayer ',
173
207
}
174
208
</script>
0 commit comments