| 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137 |
| <template>
<div @mousedown="handleMouseDown" @mouseup="end()" @mouseleave="end()" @touchstart="handleTouchStart" @touchend="end()" @touchcancel="end()">
<div class="mu-ripple-wrapper" :class="rippleWrapperClass" ref="holder">
<circle-ripple :key="ripple.key" :color="ripple.color" :opacity="ripple.opacity" :merge-style="ripple.style" v-for="ripple in ripples"></circle-ripple>
</div>
<slot></slot>
</div>
</template>
<script>
import circleRipple from './circleRipple'
import * as domUtil from '../utils/domUtil'
export default {
props: {
centerRipple: {
type: Boolean,
default: true
},
rippleWrapperClass: {
},
color: {
type: String,
default: ''
},
opacity: {
type: Number
}
},
data () {
return {
nextKey: 0,
ripples: []
}
},
mounted () {
this.ignoreNextMouseDown = false
},
methods: {
start (event, isRippleTouchGenerated) {
if (this.ignoreNextMouseDown && !isRippleTouchGenerated) {
this.ignoreNextMouseDown = false
return
}
this.ripples.push({
key: this.nextKey++,
color: this.color,
opacity: this.opacity,
style: this.centerRipple ? {} : this.getRippleStyle(event)
})
this.ignoreNextMouseDown = isRippleTouchGenerated
},
end () {
if (this.ripples.length === 0) return
this.ripples.splice(0, 1)
this.stopListeningForScrollAbort()
},
stopListeningForScrollAbort () {
if (!this.handleMove) this.handleMove = this.handleTouchMove.bind(this)
document.body.removeEventListener('touchmove', this.handleMove, false)
},
startListeningForScrollAbort (event) {
this.firstTouchY = event.touches[0].clientY
this.firstTouchX = event.touches[0].clientX
document.body.addEventListener('touchmove', this.handleMove, false)
},
handleMouseDown (event) {
if (event.button === 0) {
this.start(event, false)
}
},
handleTouchStart (event) {
if (event.touches) {
this.startListeningForScrollAbort(event)
this.startTime = Date.now()
}
this.start(event.touches[0], true)
},
handleTouchMove (event) {
const deltaY = Math.abs(event.touches[0].clientY - this.firstTouchY)
const deltaX = Math.abs(event.touches[0].clientX - this.firstTouchX)
// 判断滚动 6px
if (deltaY > 6 || deltaX > 6) this.end()
// const timeSinceStart = Math.abs(Date.now() - this.startTime)
// if (timeSinceStart > 300) {
// this.stopListeningForScrollAbort()
// return
// }
},
getRippleStyle (event) {
const el = this.$refs.holder
const elHeight = el.offsetHeight
const elWidth = el.offsetWidth
const offset = domUtil.getOffset(el)
const isTouchEvent = event.touches && event.touches.length
const pageX = isTouchEvent ? event.touches[0].pageX : event.pageX
const pageY = isTouchEvent ? event.touches[0].pageY : event.pageY
const pointerX = pageX - offset.left
const pointerY = pageY - offset.top
const topLeftDiag = this.calcDiag(pointerX, pointerY)
const topRightDiag = this.calcDiag(elWidth - pointerX, pointerY)
const botRightDiag = this.calcDiag(elWidth - pointerX, elHeight - pointerY)
const botLeftDiag = this.calcDiag(pointerX, elHeight - pointerY)
const rippleRadius = Math.max(
topLeftDiag, topRightDiag, botRightDiag, botLeftDiag
)
const rippleSize = rippleRadius * 2
const left = pointerX - rippleRadius
const top = pointerY - rippleRadius
return {
directionInvariant: true,
height: rippleSize + 'px',
width: rippleSize + 'px',
top: top + 'px',
left: left + 'px'
}
},
calcDiag (a, b) {
return Math.sqrt((a * a) + (b * b))
}
},
components: {
'circle-ripple': circleRipple
}
}
</script>
<style lang="css">
.mu-ripple-wrapper {
height: 100%;
width: 100%;
position: absolute;
top: 0;
left: 0;
overflow: hidden;
}
</style>
|