03 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
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title></title> <style>
.transition { transition: 3s background-color ease; } </style> <script src="https://unpkg.com/vue@next"></script> </head> <body> <div id="root"></div> </body> <script> const app = Vue.createApp({ data() { return { styleObj: { background: 'blue' } } }, methods: { handleClick() { if(this.styleObj.background === 'blue') { this.styleObj.background = 'green'; }else { this.styleObj.background = 'blue' } } }, template: ` <div> <div class="transition" :style="styleObj">hello world</div> <button @click="handleClick">切换</button> </div> ` }); const vm = app.mount('#root'); </script> </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
| .v-enter-from{} .v-enter-from, .v-leave-active{ transition: 3s background-color ease; } .v-enter-to{} .v-leave-to{}
@keyframes shake { 0% { transform: translateX(-100px) } 50% { transform: translateX(-50px) } 100% { transform: translateX(50px) } } .v-leave-active { animation: shake 3s; } .v-enter-active { animation: shake 3s; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| const app = Vue.createApp({ data() { return { show: false } }, methods: { handleClick() { this.show = !this.show; } }, template: ` <div> <transition> <div v-if="show">hello world</div> </transition> <button @click="handleClick">切换</button> </div> ` });
|
transition的name命名,也可以在标签里直接重命名
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
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title></title> <style> @keyframes shake { 0% { transform: translateX(-100px) } 50% { transform: translateX(-50px) } 100% { transform: translateX(50px) } } .hello-leave-active { animation: shake 3s; } .hello-enter-active { animation: shake 3s; } </style> <script src="https://unpkg.com/vue@next"></script> </head> <body> <div id="root"></div> </body> <script> const app = Vue.createApp({ data() { return { show: false } }, methods: { handleClick() { this.show = !this.show; } }, template: ` <div> <transition name="hello"> <div v-if="show">hello world</div> </transition> <button @click="handleClick">切换</button> </div> ` }); const vm = app.mount('#root'); </script> </html>
|
使用animate.css网站的动画Animate.css | 一个跨浏览器的 CSS 动画库。 中文
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
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css" /> <script src="https://unpkg.com/vue@next"></script> </head> <body> <div id="root"></div> </body> <script> const app = Vue.createApp({ data() { return { show: false } }, methods: { handleClick() { this.show = !this.show; } }, template: ` <div> <transition enter-active-class="animate__animated animate__bounce" leave-active-class="animate__animated animate__bounce" > <div v-show="show">hello world</div> </transition> <button @click="handleClick">切换</button> </div> ` }); const vm = app.mount('#root'); </script> </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
| <style> @keyframes shake { 0% { transform: translateX(-100px) } 50% { transform: translateX(-50px) } 100% { transform: translateX(50px) } } .v-enter-from { color: red; } .v-enter-active { animation: shake 3s; transition: color 10s ease-in; } .v-leave-active { color: red; animation: shake 3s; transition: all 10s ease-in; } </style>
|
transition标签使用js执行动画
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
| const app = Vue.createApp({ data() { return { show: false } }, methods: { handleClick() { this.show = !this.show; }, handleBeforeEnter(el) { el.style.color = "red"; }, handleEnterActive(el, done) { const animation = setInterval(() => { const color = el.style.color; if(color === 'red') { el.style.color = 'green'; } else { el.style.color = 'red'; } }, 1000) setTimeout(() => { clearInterval(animation); done(); }, 3000) }, handleEnterEnd(el) { alert(123); } }, template: ` <div> <transition :css="false" @before-enter="handleBeforeEnter" @enter="handleEnterActive" @after-enter="handleEnterEnd" > <div v-show="show">hello world</div> </transition> <button @click="handleClick">切换</button> </div> ` });
|
组件和元素切换动画的实现
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
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title></title> <style> .v-leave-to { opacity: 0; } .v-enter-from { opacity: 0; } .v-enter-active, .v-leave-active { transition: opacity 1s ease-in; } .v-leave-from , .v-enter-to { opacity: 1; } </style> <script src="https://unpkg.com/vue@next"></script> </head> <body> <div id="root"></div> </body> <script> const ComponentA = { template: '<div>hello world</div>' } const ComponentB = { template: '<div>bye world</div>' } const app = Vue.createApp({ data() { return { component: 'component-a' } }, methods: { handleClick() { if(this.component === 'component-a') { this.component = 'component-b'; }else { this.component = 'component-a'; } }, }, components: { 'component-a': ComponentA, 'component-b': ComponentB, }, template: ` <div> <transition mode="out-in" appear> <component :is="component" /> </transition> <button @click="handleClick">切换</button> </div> ` }); const vm = app.mount('#root'); </script> </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
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title></title> <style> .v-enter-from { opacity: 0; transform: translateY(30px); } .v-enter-active { transition: all .5s ease-in; } .v-enter-to { opacity: 1; transform: translateY(0); } .v-move { transition: all .5s ease-in; } .list-item { display: inline-block; margin-right: 10px; } </style> <script src="https://unpkg.com/vue@next"></script> </head> <body> <div id="root"></div> </body> <script> // 列表动画的实现 const app = Vue.createApp({ data() { return { list: [1, 2, 3] } }, methods: { handleClick() { this.list.unshift(this.list.length + 1); }, }, template: ` <div> <transition-group> <span class="list-item" v-for="item in list" :key="item">{{item}}</span> </transition-group> <button @click="handleClick">增加</button> </div> ` }); const vm = app.mount('#root'); </script> </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
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title></title> <script src="https://unpkg.com/vue@next"></script> </head> <body> <div id="root"></div> </body> <script> const app = Vue.createApp({ data() { return { number: 1, animateNumber: 1 } }, methods: { handleClick() { this.number = 10; if(this.animateNumber < this.number) { const animation = setInterval(() => { this.animateNumber += 1; if(this.animateNumber === 10) { clearInterval(animation); } }, 100); } }, }, template: ` <div> <div>{{animateNumber}}</div> <button @click="handleClick">增加</button> </div> ` }); const vm = app.mount('#root'); </script> </html>
|