-
Notifications
You must be signed in to change notification settings - Fork 16
/
Copy pathsvg任意元素水波纹.html
139 lines (124 loc) · 4.57 KB
/
svg任意元素水波纹.html
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
138
<body>
<!-- 注意一下这个文件,需要跑http服务,否则svg内feImage生效,不过feDisplacementMap不生效。 -->
<svg class="svg-filters" style="display:none">
<defs>
<filter id="filter-ripple-1">
<feImage id="svgFeImage" xlink:href="./ripple-gray.png" x="0" y="0" width="0" height="0" result="ripple"></feImage>
<feDisplacementMap id="feMap" xChannelSelector="R" yChannelSelector="G" color-interpolation-filters="sRGB" in="SourceGraphic" in2="ripple" scale="0"></feDisplacementMap>
<feComposite operator="in" in2="ripple"></feComposite>
<!-- 这个看情况
上面那个是filter,
下面那个是原图,有filter的时候是否显示原图,具体效果多调整。
-->
<!-- <feComposite in2="SourceGraphic"></feComposite> -->
</filter>
</defs>
</svg>
<div style="display: flex;">
<button id="button" type="button" class="element ui-button ui-button-primary" style="">click me</button>
<span style="flex-grow:1"></span>
<img class="target" src="./vue.png">
</div>
<script>
let ele = document.querySelector('.element')
let img = document.querySelector('.target')
const waterWrapper = () => {
let waters = []
return (e) => {
waters.map((item) => item.cacel())
waters = []
waters.push(water(e))
}
}
const waterf = waterWrapper()
img.onclick = waterf
ele.onclick = waterf
function water(e) {
let processing = true
let feMap = document.querySelector('#feMap')
let svgFeImage = document.querySelector('#svgFeImage')
let scale = 10
let size = 0
let speed = 0.2
let { offsetX, offsetY } = e
let { clientWidth, clientHeight } = e.target
clientWidth *= 2
e.target.style = 'filter: url(#filter-ripple-1);'
let max = 20
let times = clientWidth / (max / speed) * 2
let state = false
// 一个分两段的动画,
// 前一段scale逐渐增加
// 后一段scale逐渐减少
// 主要的视觉效果由前段动画完成。
// 后段动画主要是为了恢复平静时更加平滑。
let p = () => {
if (!processing) {
return
}
if (scale < max && !state) {
scale += speed
size += times
feMap.scale.baseVal = scale
svgFeImage.height.baseVal.value = size
svgFeImage.width.baseVal.value = size
svgFeImage.x.baseVal.value = offsetX - size / 2
svgFeImage.y.baseVal.value = offsetY - size / 2
if (scale >= max) {
state = true
}
window.requestAnimationFrame(p)
return
} else if (scale > 0) {
scale -= speed * 5
feMap.scale.baseVal = scale
size += times
svgFeImage.height.baseVal.value = size
svgFeImage.width.baseVal.value = size
svgFeImage.x.baseVal.value = offsetX - size / 2
svgFeImage.y.baseVal.value = offsetY - size / 2
window.requestAnimationFrame(p)
return
}
e.target.style = ''
}
p()
return {
cacel: () => {
processing = false
e.target.style = ''
}
}
}
</script>
</body>
<style>
.element {
display: inline-block;
line-height: 20px;
font-size: 14px;
text-align: center;
color: #4c5161;
border: 1px solid #d0d0d5;
border-radius: 4px;
padding: 9px 15px;
width: 74px;
height: 40px;
min-width: 50px;
background-color: #fff;
background-repeat: no-repeat;
background-position: center;
text-decoration: none;
-webkit-transition: border-color .15s,background-color .15s,opacity .15s;
transition: border-color .15s,background-color .15s,opacity .15s;
cursor: pointer;
overflow: visible;
outline: none;
}
.target {
overflow: hidden;
/* filter: url(#filter-ripple-1); */
}
.element:hover {
}
</style>