forked from vuejs/docs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathElasticHeader.vue
111 lines (102 loc) · 3.52 KB
/
ElasticHeader.vue
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
<script setup>
import { reactive, computed } from 'vue'
import dynamics from 'dynamics.js'
const headerHeight = 120
let isDragging = false
const start = { x: 0, y: 0 }
const c = reactive({ x: headerHeight, y: headerHeight })
const headerPath = computed(() => {
return `M0,0 L320,0 320,${headerHeight}Q${c.x},${c.y} 0,${headerHeight}`
})
const contentPosition = computed(() => {
const dy = c.y - headerHeight
const dampen = dy > 0 ? 2 : 4
return {
transform: `translate(0,${dy / dampen}px)`
}
})
function startDrag(e) {
e = e.changedTouches ? e.changedTouches[0] : e
isDragging = true
start.x = e.pageX
start.y = e.pageY
}
function onDrag(e) {
e = e.changedTouches ? e.changedTouches[0] : e
if (isDragging) {
c.x = headerHeight + (e.pageX - start.x)
const dy = e.pageY - start.y
const dampen = dy > 0 ? 1.5 : 4
c.y = headerHeight + dy / dampen
}
}
function stopDrag() {
if (isDragging) {
isDragging = false
dynamics.animate(
c,
{ x: headerHeight, y: headerHeight },
{ type: dynamics.spring, duration: 700, friction: 280 }
)
}
}
</script>
<template>
<div
class="draggable"
@mousedown="startDrag"
@mousemove="onDrag"
@mouseup="stopDrag"
@mouseleave="stopDrag"
@touchstart.prevent="startDrag"
@touchmove.prevent="onDrag"
@touchend.prevent="stopDrag"
>
<svg class="bg" width="320" height="560">
<path :d="headerPath" fill="#3F51B5"></path>
</svg>
<div class="header">Drag Me</div>
<div class="content" :style="contentPosition">
<a
href="https://play.vuejs.org/#eNqlVmtv2zYU/SsXboE6mC3bSdwVmpM9MAz9sAIdsA8b5gGhRUrWKpEESTl2DP/3HZKSbbkuUKBA4Ij3ce65D15pP/hZ62TTiEE6WNjMlNqRFa7Rj0tZ1loZR3sygmWu3IgRZarWjROcDpQbVdMbeL45WvKdZHWZ2VbXHZP/LGyWMlPSOloLxoV5L8pi7eiBZrdTr6uEo9L+alhRlLKAPGeVFZ2PdQzwD6CyTWk6oh1+6dBpM2g6isNgch4jWPeCHm4u2Xxkbg2QLrvh8IYeHmm/lARg1xhJTx+moyn9fnfr//nf1/tzzMMfr/dZsj1AnCW7Azhe6J+W8jwsfp2Q7qOypSuV/ELsaMt3Xp3saNxL48yA1Vp4DFg+ojA/0i2ldH/GPqAROcOkzZWpU3oKzxVzYui5wnPS4hz09gZsydc3Us4bidqCZWiD79FQ3ERMgagiydZMFoL/qZpsLSziX4r+mf4LRmgn9ZvsTBOEATjZBjDNCvHXSeiTj8K/wadHR8lv5ZLT8MSnhUFVA5PeyHxHw5YZutCyRW2C9alJLc+jya5n8VmXZsm865MP6hEugp61pevIRUOUDjVouX8hoWsXy8uPF5ThBvtRiGKQGXVPX3OdzozdTov0hGu1QdAR8cYwTzil76e4vrkpA/+Ubt+Fe+ydQzljhotJ3ETYQTg4UWs/qDgRLXi5aQtWMWsflgPuU2OrSiwHUfFTrRoruHqW0B5H9qh1fgyC+Ko6ONdqI6CNA9b3vK4KXo0OiLElfS8h+TVdcKsEC5B9bcgW+dpNcUx1BR09l9ytccASwmkdeoDj/C2OrRPctN9oqQ962nAwz8uqguzV3W/z2S9zOCwm3rILNkG07hmFPgaOGDD3/OiDWEygvWbY7jVESq3bVT6ti1UHkPeiqtQJontaTM46jWMAIJspLTgkybHRcaxXLPtUGNVIPs5UpUxKr/I8/yGo1HZs1wwj4N8T93pLs7f4McWKYdv5F4j/S2bzm2AeKpr6ra63QRCLium87yRouskrj7cuORcyCGtmcKfgCCtijVNBqttEUyxfJIN3UhA7sXVjVpUFFBnqIUwQ56jO2JYvuDUzED3JnlsOd9NpEGJQzNgPSwahVDKirpRBY8aG8bKxKb0LCLhByaqIVTqxYSurKrxhIhulUZrwWIkciPH5ZVxKLvw7toWJjccFT9o2XqL2cjy6z2IlGOe4/rFAp8aUL0HYUoeoF6t78/U72nUEXwvnRYqFuxX153VbqYpHYEy1nySM0GA0iF8q45ppfJUoia+eEG/ZKuxykHZbE6vl9AHj5bgHzmmbTiYZl4n9tNMYwYSLzaRn2O2xweF/7cIdbA=="
target="_blank"
>Source code</a
>
</div>
</div>
</template>
<style scoped>
.draggable {
background-color: #fff;
box-shadow: var(--vt-shadow-2);
width: 320px;
height: 240px;
overflow: hidden;
margin: 30px auto;
position: relative;
text-align: center;
font-size: 14px;
font-weight: 300;
user-select: none;
border-radius: 8px;
}
.bg {
position: absolute;
top: 0;
left: 0;
z-index: 0;
}
.header,
.content {
position: relative;
z-index: 1;
padding: 30px;
box-sizing: border-box;
}
.header {
color: #fff;
height: 120px;
font-size: 2em;
font-weight: bold;
}
</style>