Skip to content

Commit c5cf5ab

Browse files
committed
additional animation techniques
1 parent 93e0e94 commit c5cf5ab

File tree

7 files changed

+429
-0
lines changed

7 files changed

+429
-0
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
"dependencies": {
88
"@vue/repl": "^0.4.7",
99
"@vue/theme": "^0.1.23",
10+
"dynamics.js": "^1.1.5",
1011
"gsap": "^3.9.0",
1112
"vitepress": "^0.20.9",
1213
"vue": "^3.2.25"

pnpm-lock.yaml

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/guide/extras/animation.md

Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,207 @@
1+
<script setup>
2+
import ElasticHeader from './demos/ElasticHeader.vue'
3+
import NotActivated from './demos/NotActivated.vue'
4+
import Colors from './demos/Colors.vue'
5+
import AnimateWatcher from './demos/AnimateWatcher.vue'
6+
</script>
7+
18
# Animation Techniques
9+
10+
Vue provides the [`<Transition>`](/guide/built-ins/transition.html) and [`<TransitionGroup>`](guide/built-ins/transition-group.html) components for handling enter / leave and list transitions. However, there are many other ways of using animations on the web, even in a Vue application. Here we will discuss a few additional techniques.
11+
12+
## Class-based Animations
13+
14+
For elements that are not entering / leaving the DOM, we can trigger animations by dynamically adding a CSS class:
15+
16+
<div class="composition-api">
17+
18+
```js
19+
const notActivated = ref(false)
20+
21+
function warnNotActivated() {
22+
notActivated.value = true
23+
setTimeout(() => {
24+
notActivated.value = false
25+
}, 1500)
26+
}
27+
```
28+
29+
</div>
30+
<div class="options-api">
31+
32+
```js
33+
export default {
34+
data() {
35+
return {
36+
notActivated: false
37+
}
38+
},
39+
methods: {
40+
warnNotActivated() {
41+
this.notActivated = true
42+
setTimeout(() => {
43+
this.notActivated = false
44+
}, 1500)
45+
}
46+
}
47+
}
48+
```
49+
50+
</div>
51+
52+
```vue-html
53+
<div :class="{ shake: notActivated }">
54+
<button @click="warnNotActivated">Click me</button>
55+
<span v-if="notActivated">This feature is not activated.</span>
56+
</div>
57+
```
58+
59+
```css
60+
.shake {
61+
animation: shake 0.82s cubic-bezier(0.36, 0.07, 0.19, 0.97) both;
62+
transform: translate3d(0, 0, 0);
63+
}
64+
65+
@keyframes shake {
66+
10%,
67+
90% {
68+
transform: translate3d(-1px, 0, 0);
69+
}
70+
71+
20%,
72+
80% {
73+
transform: translate3d(2px, 0, 0);
74+
}
75+
76+
30%,
77+
50%,
78+
70% {
79+
transform: translate3d(-4px, 0, 0);
80+
}
81+
82+
40%,
83+
60% {
84+
transform: translate3d(4px, 0, 0);
85+
}
86+
}
87+
```
88+
89+
<NotActivated />
90+
91+
## State-driven Animations
92+
93+
Some transition effects can be applied by interpolating values, for instance by binding a style to an element while an interaction occurs. Take this example for instance:
94+
95+
<div class="composition-api">
96+
97+
```js
98+
const x = ref(0)
99+
100+
function onMousemove(e) {
101+
x.value = e.clientX
102+
}
103+
```
104+
105+
</div>
106+
<div class="options-api">
107+
108+
```js
109+
export default {
110+
data() {
111+
return {
112+
x: 0
113+
}
114+
},
115+
methods: {
116+
onMousemove(e) {
117+
this.x = e.clientX
118+
}
119+
}
120+
}
121+
```
122+
123+
</div>
124+
125+
```vue-html
126+
<div
127+
@mousemove="onMousemove"
128+
:style="{ backgroundColor: `hsl(${x}, 80%, 50%)` }"
129+
class="movearea"
130+
>
131+
<p>Move your mouse across this div...</p>
132+
<p>x: {{ x }}</p>
133+
</div>
134+
```
135+
136+
```css
137+
.movearea {
138+
transition: 0.3s background-color ease;
139+
}
140+
```
141+
142+
<Colors />
143+
144+
In addition to color, you can also use style bindings to animate transform, width, or height. You can even animate SVG paths using spring physics - after all, they are all attribute data bindings:
145+
146+
<ElasticHeader />
147+
148+
## Animating with Watchers
149+
150+
With some creativity, we can use watchers to animate anything based on some numerical state. For example we can animate the number itself:
151+
152+
<div class="composition-api">
153+
154+
```js
155+
import { ref, reactive, watch } from 'vue'
156+
import gsap from 'gsap'
157+
158+
const number = ref(0)
159+
const tweened = reactive({
160+
number: 0
161+
})
162+
163+
watch(number, (n) => {
164+
gsap.to(tweened, { duration: 0.5, number: Number(n) || 0 })
165+
})
166+
```
167+
168+
</div>
169+
<div class="options-api">
170+
171+
```js
172+
import gsap from 'gsap'
173+
174+
export default {
175+
data() {
176+
return {
177+
number: 0,
178+
tweened: 0
179+
}
180+
},
181+
watch: {
182+
number(n) {
183+
gsap.to(this, { duration: 0.5, tweened: Number(n) || 0 })
184+
}
185+
}
186+
}
187+
```
188+
189+
</div>
190+
191+
```vue-html
192+
Type a number: <input v-model.number="number" />
193+
<p>{{ tweened.number.toFixed(0) }}</p>
194+
```
195+
196+
<AnimateWatcher />
197+
198+
<div class="composition-api">
199+
200+
[Try it in the Playground](https://sfc.vuejs.org/#eyJBcHAudnVlIjoiPHNjcmlwdCBzZXR1cD5cbmltcG9ydCB7IHJlZiwgcmVhY3RpdmUsIHdhdGNoIH0gZnJvbSAndnVlJ1xuaW1wb3J0IGdzYXAgZnJvbSAnZ3NhcCdcblxuY29uc3QgbnVtYmVyID0gcmVmKDApXG5jb25zdCB0d2VlbmVkID0gcmVhY3RpdmUoe1xuICBudW1iZXI6IDBcbn0pXG5cbndhdGNoKFxuICBudW1iZXIsXG4gIChuKSA9PiB7XG4gICAgZ3NhcC50byh0d2VlbmVkLCB7IGR1cmF0aW9uOiAwLjUsIG51bWJlcjogTnVtYmVyKG4pIHx8IDAgfSlcbiAgfVxuKVxuPC9zY3JpcHQ+XG5cbjx0ZW1wbGF0ZT5cbiAgPGRpdiBjbGFzcz1cImRlbW9cIj5cbiAgICBUeXBlIGEgbnVtYmVyOiA8aW5wdXQgdi1tb2RlbC5udW1iZXI9XCJudW1iZXJcIiAvPlxuICAgIDxwIGNsYXNzPVwiYmlnLW51bWJlclwiPnt7IHR3ZWVuZWQubnVtYmVyLnRvRml4ZWQoMCkgfX08L3A+XG4gIDwvZGl2PlxuPC90ZW1wbGF0ZT5cblxuPHN0eWxlPlxuLmJpZy1udW1iZXIge1xuICBmb250LXdlaWdodDogYm9sZDtcbiAgZm9udC1zaXplOiAyZW07XG59XG48L3N0eWxlPlxuIiwiaW1wb3J0LW1hcC5qc29uIjoie1xuICBcImltcG9ydHNcIjoge1xuICAgIFwiZ3NhcFwiOiBcImh0dHBzOi8vdW5wa2cuY29tL2dzYXA/bW9kdWxlXCIsXG4gICAgXCJ2dWVcIjogXCJodHRwczovL3NmYy52dWVqcy5vcmcvdnVlLnJ1bnRpbWUuZXNtLWJyb3dzZXIuanNcIlxuICB9XG59In0=)
201+
202+
</div>
203+
<div class="options-api">
204+
205+
[Try it in the Playground](https://sfc.vuejs.org/#eyJBcHAudnVlIjoiPHNjcmlwdD5cbmltcG9ydCBnc2FwIGZyb20gJ2dzYXAnXG5cbmV4cG9ydCBkZWZhdWx0IHtcbiAgZGF0YSgpIHtcbiAgICByZXR1cm4ge1xuICAgICAgbnVtYmVyOiAwLFxuICAgICAgdHdlZW5lZDogMFxuICAgIH1cbiAgfSxcbiAgd2F0Y2g6IHtcbiAgICBudW1iZXIobikge1xuICAgICAgZ3NhcC50byh0aGlzLCB7IGR1cmF0aW9uOiAwLjUsIHR3ZWVuZWQ6IE51bWJlcihuKSB8fCAwIH0pXG4gICAgfVxuICB9XG59XG48L3NjcmlwdD5cblxuPHRlbXBsYXRlPlxuXHRUeXBlIGEgbnVtYmVyOiA8aW5wdXQgdi1tb2RlbC5udW1iZXI9XCJudW1iZXJcIiAvPlxuXHQ8cCBjbGFzcz1cImJpZy1udW1iZXJcIj57eyB0d2VlbmVkLnRvRml4ZWQoMCkgfX08L3A+XG48L3RlbXBsYXRlPlxuXG48c3R5bGU+XG4uYmlnLW51bWJlciB7XG4gIGZvbnQtd2VpZ2h0OiBib2xkO1xuICBmb250LXNpemU6IDJlbTtcbn1cbjwvc3R5bGU+IiwiaW1wb3J0LW1hcC5qc29uIjoie1xuICBcImltcG9ydHNcIjoge1xuICAgIFwiZ3NhcFwiOiBcImh0dHBzOi8vdW5wa2cuY29tL2dzYXA/bW9kdWxlXCIsXG4gICAgXCJ2dWVcIjogXCJodHRwczovL3NmYy52dWVqcy5vcmcvdnVlLnJ1bnRpbWUuZXNtLWJyb3dzZXIuanNcIlxuICB9XG59In0=)
206+
207+
</div>
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<script setup>
2+
import { ref, reactive, watch } from 'vue'
3+
import gsap from 'gsap'
4+
5+
const number = ref(0)
6+
const tweened = reactive({
7+
number: 0
8+
})
9+
10+
watch(
11+
number,
12+
(n) => {
13+
gsap.to(tweened, { duration: 0.5, number: Number(n) || 0 })
14+
}
15+
)
16+
</script>
17+
18+
<template>
19+
<div class="demo">
20+
Type a number: <input v-model.number="number" />
21+
<p class="big-number">{{ tweened.number.toFixed(0) }}</p>
22+
</div>
23+
</template>
24+
25+
<style>
26+
.big-number {
27+
font-weight: bold;
28+
font-size: 2em;
29+
}
30+
</style>

src/guide/extras/demos/Colors.vue

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<script setup>
2+
let x = $ref(0)
3+
function onMousemove(e) {
4+
x = e.clientX
5+
}
6+
</script>
7+
8+
<template>
9+
<div
10+
@mousemove="onMousemove"
11+
:style="{ backgroundColor: `hsl(${x}, 80%, 50%)` }"
12+
class="demo movearea"
13+
>
14+
<p>Move your mouse across this div...</p>
15+
<p>x: {{ x }}</p>
16+
</div>
17+
</template>
18+
19+
<style>
20+
.movearea {
21+
color: #fff;
22+
transition: 0.3s background-color ease;
23+
border: none;
24+
}
25+
</style>

0 commit comments

Comments
 (0)