Le statut Vue abuse de la « montre » de l'auditeur pour la surveillance. Grâce à l'écouteur, la mise à jour de la valeur de toute propriété numérique peut être surveillée. Les écouteurs Vue sont fournis aux développeurs pour surveiller les modifications de certaines données et effectuer certaines opérations en fonction des modifications de ces données. Il convient de noter que l'écouteur est essentiellement une fonction. Si vous souhaitez surveiller les modifications des données, utilisez ces données comme nom de fonction.
L'environnement d'exploitation de ce tutoriel : système windows7, version vue3, ordinateur DELL G3.
L'état est une donnée, qui comprend des valeurs numériques, des valeurs de couleur, des valeurs d'attribut, etc., donc la transition d'état fait référence à l'effet de transition des données elles-mêmes.
Vue recommande une approche de « mise à jour réactive et basée sur les données » pour réaliser la transition d'état. L'idée principale est de convertir un état en variable réactive, puis d'utiliser certaines bibliothèques dynamiques pour mettre à jour la variable réactive, pilotant ainsi la mise à jour réactive de Vue et obtenant un effet de transition dynamique.
Le système de transition de Vue offre de nombreuses façons simples d'animer l'entrée, la sortie et les listes. Qu'en est-il de l'animation des éléments de données eux-mêmes, tels que :
Ces données sont soit stockées sous forme numérique eux-mêmes, ou peuvent être convertis en une valeur numérique. Avec ces valeurs à l'esprit, nous pouvons combiner la réactivité et le système de composants de Vue et utiliser une bibliothèque tierce pour implémenter l'état de transition des éléments de commutation.
Grâce à l'écouteur, nous pouvons surveiller la mise à jour numérique de toute propriété numérique.
Les auditeurs Vue sont fournis aux développeurs pour surveiller les modifications de certaines données et effectuer certaines opérations en fonction des modifications de ces données.
Mais veuillez noter : un auditeur est essentiellement une fonction. Si vous souhaitez écouter les changements dans les données, utilisez ces données comme nom de fonction
Cela peut sembler abstrait, alors jetons d'abord un coup d'œil à l'utilisation de GreenSock An. exemple :
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.2.4/gsap.min.js"></script> <div id="animated-number-demo"> <input v-model.number="number" type="number" step="20"> <p>{{ animatedNumber }}</p> </div> <script> new Vue({ el: '#animated-number-demo', data: { number: 0, tweenedNumber: 0 }, computed: { animatedNumber: function() { return this.tweenedNumber.toFixed(0); } }, watch: { number: function(newValue) { gsap.to(this.$data, { duration: 0.5, tweenedNumber: newValue }); } } }) </script>
Lorsque vous mettez à jour la valeur, l'animation sera déclenchée. C'est une bonne démonstration, mais pour les valeurs qui ne peuvent pas être stockées directement comme les nombres, comme la valeur de color en CSS, à travers l'exemple suivant nous implémenterons un exemple via Tween.js et Color.js :
<script src="https://cdn.jsdelivr.net/npm/tween.js@16.3.4"></script> <script src="https://cdn.jsdelivr.net/npm/color-js@1.0.3"></script> <div id="example-7"> <input v-model="colorQuery" v-on:keyup.enter="updateColor" placeholder="Enter a color" > <button v-on:click="updateColor">Update</button> <p>Preview:</p> <span v-bind:style="{ backgroundColor: tweenedCSSColor }" class="example-7-color-preview" ></span> <p>{{ tweenedCSSColor }}</p> </div> <script> var Color = net.brehaut.Color new Vue({ el: '#example-7', data: { colorQuery: '', color: { red: 0, green: 0, blue: 0, alpha: 1 }, tweenedColor: {} }, created: function () { this.tweenedColor = Object.assign({}, this.color) }, watch: { color: function () { function animate () { if (TWEEN.update()) { requestAnimationFrame(animate) } } new TWEEN.Tween(this.tweenedColor) .to(this.color, 750) .start() animate() } }, computed: { tweenedCSSColor: function () { return new Color({ red: this.tweenedColor.red, green: this.tweenedColor.green, blue: this.tweenedColor.blue, alpha: this.tweenedColor.alpha }).toCSS() } }, methods: { updateColor: function () { this.color = new Color(this.colorQuery).toRGB() this.colorQuery = '' } } }) .example-7-color-preview { display: inline-block; width: 50px; height: 50px; } </script>
Tout comme le composant de transition de Vue, la transition d'état derrière les données sera mise à jour en temps réel, ce qui est très utile pour la conception de prototypes. Lorsque vous modifiez certaines variables, même un simple polygone SVG peut produire de nombreux effets inimaginables.
<!DOCTYPE html> <html> <head> <title>Dynamic State Transitions</title> <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.18.5/TweenLite.min.js"></script> <script src="https://unpkg.com/vue"></script> <style> svg { display: block; } polygon { fill: #41b883; } circle { fill: transparent; stroke: #35495e; } input[type="range"] { display: block; width: 100%; margin-bottom: 15px; } </style> </head> <body> <div id="app"> <svg width="200" height="200"> <polygon :points="points"></polygon> <circle cx="100" cy="100" r="90"></circle> </svg> <label>Sides: {{ sides }}</label> <input type="range" min="3" max="500" v-model.number="sides" /> <label>Minimum Radius: {{ minRadius }}%</label> <input type="range" min="0" max="90" v-model.number="minRadius" /> <label>Update Interval: {{ updateInterval }} milliseconds</label> <input type="range" min="10" max="2000" v-model.number="updateInterval" /> </div> <script> new Vue({ el: "#app", data: function() { var defaultSides = 10; var stats = Array.apply(null, { length: defaultSides }).map( function() { return 100; } ); return { stats: stats, points: generatePoints(stats), sides: defaultSides, minRadius: 50, interval: null, updateInterval: 500 }; }, watch: { sides: function(newSides, oldSides) { var sidesDifference = newSides - oldSides; if (sidesDifference > 0) { for (var i = 1; i <= sidesDifference; i++) { this.stats.push(this.newRandomValue()); } } else { var absoluteSidesDifference = Math.abs(sidesDifference); for (var i = 1; i <= absoluteSidesDifference; i++) { this.stats.shift(); } } }, stats: function(newStats) { TweenLite.to(this.$data, this.updateInterval / 1000, { points: generatePoints(newStats) }); }, updateInterval: function() { this.resetInterval(); } }, mounted: function() { this.resetInterval(); }, methods: { randomizeStats: function() { var vm = this; this.stats = this.stats.map(function() { return vm.newRandomValue(); }); }, newRandomValue: function() { return Math.ceil( this.minRadius + Math.random() * (100 - this.minRadius) ); }, resetInterval: function() { var vm = this; clearInterval(this.interval); this.randomizeStats(); this.interval = setInterval(function() { vm.randomizeStats(); }, this.updateInterval); } } }); function valueToPoint(value, index, total) { var x = 0; var y = -value * 0.9; var angle = ((Math.PI * 2) / total) * index; var cos = Math.cos(angle); var sin = Math.sin(angle); var tx = x * cos - y * sin + 100; var ty = x * sin + y * cos + 100; return { x: tx, y: ty }; } function generatePoints(stats) { var total = stats.length; return stats .map(function(stat, index) { var point = valueToPoint(stat, index, total); return point.x + "," + point.y; }) .join(" "); } </script> </body> </html>
Gérer trop de transitions d'état augmentera rapidement la complexité des instances ou des composants Vue Heureusement, de nombreuses animations peuvent être extraites vers des sous-composants dédiés. Réécrivons l'exemple précédent :
<script src="https://cdn.jsdelivr.net/npm/tween.js@16.3.4"></script> <div id="example-8"> <input v-model.number="firstNumber" type="number" step="20"> + <input v-model.number="secondNumber" type="number" step="20"> = {{ result }} <p> <animated-integer v-bind:value="firstNumber"></animated-integer> + <animated-integer v-bind:value="secondNumber"></animated-integer> = <animated-integer v-bind:value="result"></animated-integer> </p> </div> <script> // 这种复杂的补间动画逻辑可以被复用 // 任何整数都可以执行动画 // 组件化使我们的界面十分清晰 // 可以支持更多更复杂的动态过渡 // 策略。 Vue.component('animated-integer', { template: '<span>{{ tweeningValue }}</span>', props: { value: { type: Number, required: true } }, data: function () { return { tweeningValue: 0 } }, watch: { value: function (newValue, oldValue) { this.tween(oldValue, newValue) } }, mounted: function () { this.tween(0, this.value) }, methods: { tween: function (startValue, endValue) { var vm = this function animate () { if (TWEEN.update()) { requestAnimationFrame(animate) } } new TWEEN.Tween({ tweeningValue: startValue }) .to({ tweeningValue: endValue }, 500) .onUpdate(function () { vm.tweeningValue = this.tweeningValue.toFixed(0) }) .start() animate() } } }) // 所有的复杂度都已经从 Vue 的主实例中移除! new Vue({ el: '#example-8', data: { firstNumber: 20, secondNumber: 40 }, computed: { result: function () { return this.firstNumber + this.secondNumber } } }) </script>
Nous pouvons l'utiliser en conjonction avec des composants. Cette section parle de diverses stratégies de transition et du système de transition intégré de Vue. En bref, il n'y a pratiquement aucun obstacle à la réalisation des divers effets de transition.
4. Donnez vie au designUne seule animation peut donner vie. Malheureusement, lorsque les concepteurs créent des icônes, des logos et des mascottes, ils sont souvent livrés sous forme d'images ou de SVG statiques. Ainsi, même si le chat poulpe de GitHub, l’oiseau de Twitter et de nombreux autres logos ressemblent à des êtres vivants, ils n’ont pas vraiment l’air vivants. Vue peut vous aider. Étant donné que la nature du SVG est constituée de données, nous n'avons besoin que d'exemples de ces animaux excités, réfléchissants ou alertes. Vue peut ensuite vous aider à réaliser l'animation de transition entre ces états pour créer votre page d'accueil, vos instructions de chargement et des invites plus émotionnelles. Sarah Drasner a montré la démo suivante, qui combine des changements d'état liés au temps et à l'interaction : Source :https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.10/vue.min.js
https://cdnjs.cloudflare.com/ajax/libs/gsap/1.19.1/TweenMax.min.js
HTML代码
<div id="app" @mousemove="coordinates"> <p>Move your mouse or tap</p> <svg id="walle" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 139.4 129.4"> <defs> <clipPath id="clip-path" transform="translate(-81.8 -924.4)"> <circle cx="140.5" cy="978.2" r="4.3" fill="none"/> </clipPath> <clipPath id="clip-path-2" transform="translate(-81.8 -924.4)"> <path d="M148.5,976.5s1.3,5.2-3.2,6.7l3.4,3.6,9.3-2.1-5-8.3Z" fill="none"/> </clipPath> <clipPath id="clip-path-3" transform="translate(-81.8 -924.4)"> <circle cx="155.8" cy="983.6" r="4.3" fill="none"/> </clipPath> <clipPath id="clip-path-4" transform="translate(-81.8 -924.4)"> <path d="M130.4,1007.6s1.3-.4,1.9.7a1.5,1.5,0,0,1-.3,1.8c-.2.3-4.5,2.9-4.5,2.9l-20.6,13.7-3.5-6.4Z" fill="none"/> </clipPath> <clipPath id="clip-path-5" transform="translate(-81.8 -924.4)"> <path d="M150.6,1000s1.4.3,1.3,1.5a1.5,1.5,0,0,1-1.1,1.5c-.3.2-5.3.5-5.3.5l-24.6,2.3v-7.3Z" fill="none"/> </clipPath> </defs> <g id="Layer_3" data-name="Layer 3"> <ellipse id="shadow" cx="71.5" cy="100.4" rx="26.5" ry="3.6" fill="#394848" opacity="0.35"/> </g> <g id="Layer_2" data-name="Layer 2"> <g class="head" v-bind:class="{isFlipped: flip}"> <g id="neck"> <g id="neckb"> <path d="M157.8,995.6a2.6,2.6,0,1,1-4.1-2.2,6.1,6.1,0,0,0-1.7-.3c-1-.2-.9-1.3-.8-1.8a1.6,1.6,0,0,1-.5-1.2,1.7,1.7,0,1,1,3.4,0,1.6,1.6,0,0,1-.5,1.2,5.8,5.8,0,0,0,1.7,1.8A2.6,2.6,0,0,1,157.8,995.6Z" transform="translate(-81.8 -924.4)" fill="#a2b2b3"/> <circle cx="70.6" cy="65.6" r="0.9" fill="#636767"/> <circle cx="73.3" cy="71.2" r="1.6" fill="none" stroke="#636767" stroke-miterlimit="10" stroke-width="0.5"/> </g> <g id="neckf"> <path id="wire" d="M147.3,989.3s-2-1.9-.7-3.2l3.4-3.7.3.9s-2.6,2.5-3.2,3.3.9,2.5.9,2.5Z" transform="translate(-81.8 -924.4)" fill="#394848"/> <path fill="#a2b2b3" d="M64.6 67.1L65.3 67.6 69.3 67.5 69.6 67 64.6 67.1z"/> <path d="M149.8,983.4l.2,2.6-1.9,2.3-1.7.2s-2.5,1.9.3,3.1h4.8s-1.9-2,.5-2.8l-1.5-.2,2.4-2.3L152,983Z" transform="translate(-81.8 -924.4)" fill="#ddeced"/> <path d="M147,992l4.1-.2,1.1,1.3h2.1a3,3,0,0,0-1.7,2.4h-7.6a2.6,2.6,0,0,1,2.3-2.6Z" transform="translate(-81.8 -924.4)" fill="#ddeced"/> </g> </g> <g id="eyecontain"> <g id="eyes" :style="{ transform:`translate3d(${x}px, ${y}px, 0)`}"> <g id="lefteye"> <path id="lefteyeb2" d="M143.8,972.7l-6.1,1.1a6.2,6.2,0,0,0-4.1,8s2.3,4.4,6.6,3.7l5.4-.6a5.7,5.7,0,0,0,4.4-6l-.6-4.1S148.7,971.8,143.8,972.7Z" transform="translate(-81.8 -924.4)" fill="#a2b2b3"/> <path id="lefteyeb1" d="M145.1,972.1l-8.1,1s-5.8,1.6-4.1,7.3a4.9,4.9,0,0,0,5.6,3.4l5.4-.6s4.6-.8,4.4-5.4l-.6-4.6S147.9,971.6,145.1,972.1Z" transform="translate(-81.8 -924.4)" fill="#ddeced"/> <g id="lefteyeball"> <circle cx="58.7" cy="53.8" r="4.3" fill="#0c1112"/> <g clip-path="url(#clip-path)"> <circle id="ball" cx="59.7" cy="54.8" r="4.3" fill="#394848"/> </g> <circle id="glimmer" cx="61.5" cy="51.2" r="1.4" fill="#fff"/> </g> </g> <g id="eyespace"> <g clip-path="url(#clip-path-2)"> <circle cx="66.4" cy="56.1" r="3.6" fill="#f49123"/> </g> </g> <g id="righteye"> <path id="righteyeb2" d="M158.8,978.7l4.1,4.7a6.2,6.2,0,0,1-1.8,8.8s-4.5,2.1-7.4-1.2l-3.9-3.9a5.7,5.7,0,0,1,.2-7.4l3-2.8S155.5,974.9,158.8,978.7Z" transform="translate(-81.8 -924.4)" fill="#a2b2b3"/> <path id="righteyeb1" d="M156.4,976l5.4,6.1s3.3,5-1.8,8.2a4.9,4.9,0,0,1-6.4-1.2l-3.7-4s-2.9-3.6.3-7l3.5-3.1S154.7,973.8,156.4,976Z" transform="translate(-81.8 -924.4)" fill="#ddeced"/> <g id="righteyeball"> <circle cx="74" cy="59.2" r="4.3" fill="#0c1112"/> <g clip-path="url(#clip-path-3)"> <circle id="ball-2" data-name="ball" cx="75" cy="60.2" r="4.3" fill="#394848"/> </g> <circle id="glimmer-2" data-name="glimmer" cx="74.7" cy="56.1" r="1.4" fill="#fff"/> </g> </g> </g> </g> </g> <g class="body"> <g id="backwheel"> <path d="M149.9,1007.2l-4.8-.2s-.6-.2-2,1.2l-12.5,12.7s-1.4,2.3.3,3.5a3.9,3.9,0,0,0,3.1.8h7.1Z" transform="translate(-81.8 -924.4)" fill="#394848"/> <path d="M152.4,1009.2s-2-4.6-6.5-.1l-11,11.2s-3.8,4.1,1.4,4.8h16.2s7.8.2,5.5-7.4Z" transform="translate(-81.8 -924.4)" fill="#636767"/> <path d="M151.7,1010.8s-1.7-3.8-5.3-.1l-9,9.1s-3.1,3.3,1.2,3.9h13.3s6.4.1,4.6-6Z" transform="translate(-81.8 -924.4)" fill="#0c1112"/> </g> <path d="M148.7,1024h3.2a5,5,0,0,0,2.6,1.1h-4.2S148.9,1024.7,148.7,1024Z" transform="translate(-81.8 -924.4)" fill="#0c1112"/> <g id="rightarm"> <path d="M140.9,999.3l-10.9,6.9a3.2,3.2,0,0,0-.4,4.5c1.9,2.6,5,.1,5,.1l9.2-5.1s3.8-2.3,1.9-5.1A3.8,3.8,0,0,0,140.9,999.3Z" transform="translate(-81.8 -924.4)" fill="#c6690c"/> <g clip-path="url(#clip-path-4)"> <path id="newrightarm" d="M130.6,1008.4l10.8-6.2a.6.6,0,0,1,.8,0c.3.3.8.5.1,1.1s-10.8,6.5-10.8,6.5-.8.5-1,.4-.6-.9-.6-.9S129.6,1009.1,130.6,1008.4Z" transform="translate(-81.8 -924.4)" fill="#a2b2b3"/> </g> <circle cx="48.5" cy="85" r="1.3" fill="#636767"/> <g id="backhand"> <path d="M131,1011.5c.9.6,1.6-.2,2.4-.4a3.8,3.8,0,0,1,1.5-.3c.1.8-.4,1.4-.5,2.1l-1.4.4c-1.5.7-2.8.7-3.9-.7a.9.9,0,0,0-.5-.7,2,2,0,0,1-.5-1.8c-.1-.7.5-.8.9-1s1.8.7,1.7,1.9A.5.5,0,0,0,131,1011.5Zm-1.1-.9c-.1-.3-.2-.6-.6-.6s-.6.1-.6.5a.7.7,0,0,0,.7.7C129.8,1011.2,129.9,1010.9,130,1010.7Z" transform="translate(-81.8 -924.4)" fill="#636767"/> <path d="M133.4,1016.1a3.9,3.9,0,0,1-4.3,3.6c-.9-.1-1.3-.9-1.8-1.6a5.5,5.5,0,0,1,.5-1.8c.2-.8.4-.6.8-.1a1.8,1.8,0,0,0,2.4.7Z" transform="translate(-81.8 -924.4)" fill="#424e4f"/> <path d="M129.1,1012.7c1.1,1.4,2.4,1.4,3.9.7l1.4-.4-.6,2.2-3,1.1a1.3,1.3,0,0,1-1.5-.4C128.2,1014.8,128.2,1014.1,129.1,1012.7Z" transform="translate(-81.8 -924.4)" fill="#424e4f"/> <path d="M129.1,1012.7c-1,1.4-.9,2.1.1,3.1a1.3,1.3,0,0,0,1.5.4l3-1.1-.3.9-2.4.7a1.8,1.8,0,0,1-2.4-.7c-.3-.5-.6-.7-.8.1a5.5,5.5,0,0,0-.5,1.8l-.5-.5a33.5,33.5,0,0,1,1.7-5.6A.9.9,0,0,1,129.1,1012.7Z" transform="translate(-81.8 -924.4)" fill="#394848"/> <path d="M128.7,1012a33.5,33.5,0,0,0-1.7,5.6,1.6,1.6,0,0,1-.5-2c.5-1.5.9-3,1.3-4.5v-.2a.6.6,0,0,1,.3-.6A2,2,0,0,0,128.7,1012Z" transform="translate(-81.8 -924.4)" fill="#424e4f"/> <path d="M130,1010.7c-.1.3-.2.6-.5.6a.7.7,0,0,1-.7-.7c0-.3.3-.5.6-.5S129.9,1010.3,130,1010.7Z" transform="translate(-81.8 -924.4)" fill="#424e4f"/> </g> </g> <g id="front"> <path fill="#f49123" d="M55.1 73.1H76.6V92.91999999999999H55.1z"/> <path d="M136.3,1014.3h2.8s.9-.1.9,1,.1,1.8.1,1.8a.9.9,0,0,1-.8.8h-2s-1.2-.4-1.2-1.4A4,4,0,0,1,136.3,1014.3Z" transform="translate(-81.8 -924.4)" fill="#ddeced"/> <rect x="54.8" y="72.9" width="21.2" height="7.67" rx="1" ry="1" fill="#ddeced"/> <path d="M157.1,997.9h-20c-.3,0-.5-.1-.5-.3s.2-.2.5-.2h20c.3,0,.5.1.5.3S157.4,997.9,157.1,997.9Z" transform="translate(-81.8 -924.4)" fill="#636767" opacity="0.41"/> <rect x="57.8" y="81.5" width="1.3" height="6.42" rx="0.7" ry="0.7" fill="#f2791e"/> <rect x="71.5" y="81.4" width="1.3" height="6.42" rx="0.7" ry="0.7" fill="#f2791e"/> <rect x="64.8" y="81.5" width="1.3" height="6.42" rx="0.7" ry="0.7" fill="#f2791e"/> <rect x="53.6" y="71.2" width="23" height="1.92" rx="1" ry="1" fill="#ddeced"/> <path fill="#a2b2b3" d="M59.5 73.1H70.3V79.1H59.5z"/> <path fill="#bedb45" d="M66.2 74.1H68.4V77.92999999999999H66.2z"/> <path fill="#636767" d="M61.3 74H64.2V78H61.3z"/> <circle cx="62.4" cy="75.6" r="0.5" fill="#f76f6f"/> </g> <g id="back"> <rect x="74.5" y="71.2" width="13" height="1.75" rx="0.9" ry="0.9" fill="#a2b2b3"/> <path fill="#f2791e" d="M86.3 80.4L86.3 83.1 81.2 83 76.5 87.3 76.4 80.3 86.3 80.4z"/> <path fill="#a2b2b3" d="M76.4 72.1H86.30000000000001V80.6H76.4z"/> <path d="M167.9,997.7h-9.5a.3.3,0,0,1,0-.5h9.5a.3.3,0,0,1,0,.5Z" transform="translate(-81.8 -924.4)" fill="#636767"/> <rect x="75.9" y="73" width="0.6" height="19.31" rx="0.3" ry="0.3" fill="#636767" opacity="0.34"/> </g> <g id="forwardwheel"> <path fill="none" stroke="#0c1112" stroke-linecap="round" stroke-miterlimit="10" stroke-width="0.25" d="M68.1 100.7L90.6 100.7"/> <path d="M165.8,1007.5H161s-.6-.2-1.9,1.2l-12,12.2s-1.3,2.2.3,3.3a3.8,3.8,0,0,0,3,.8h6.8Z" transform="translate(-81.8 -924.4)" fill="#0c1112" opacity="0.41"/> <path d="M167.9,1007.2l-4.8-.2s-.6-.2-2,1.2l-12.5,12.7s-1.4,2.3.3,3.5a3.9,3.9,0,0,0,3.1.8h7.1Z" transform="translate(-81.8 -924.4)" fill="#394848"/> <path d="M170.4,1009.2s-2-4.6-6.5-.1l-11,11.2s-3.8,4.1,1.4,4.8h16.2s7.8.2,5.5-7.4Z" transform="translate(-81.8 -924.4)" fill="#a2b2b3"/> <path d="M169.7,1010.8s-1.7-3.8-5.3-.1l-9,9.1s-3.1,3.3,1.2,3.9h13.3s6.4.1,4.6-6Z" transform="translate(-81.8 -924.4)" fill="#636767"/> <path d="M173.6,1017.2l-3-1.7s-11.2.1-6,8.1h5.9Z" transform="translate(-81.8 -924.4)" fill="#394848" opacity="0.78"/> <path d="M165.1,1010l1.6,4.6s-1.3-.6-1.3,1.2-3.4,3.2-3.4,3.2-1.2-.3-1.4,1.2-2.6,3.4-2.6,3.4H155s-3.5-.1-.4-3h0Z" transform="translate(-81.8 -924.4)" fill="#394848" opacity="0.78"/> <g id="wheel"> <circle cx="85.4" cy="87.6" r="2.9" fill="#a2b2b3"/> <circle cx="85.4" cy="87.6" r="2" fill="#ddeced"/> <ellipse cx="85.1" cy="87.6" rx="1.1" ry="0.8" fill="#394848"/> <circle cx="85.5" cy="87.6" r="0.8" fill="#a2b2b3"/> </g> <g id="wheel-2" data-name="wheel"> <circle cx="81" cy="92.2" r="2.9" fill="#a2b2b3"/> <circle cx="81" cy="92.2" r="2" fill="#ddeced"/> <ellipse cx="80.7" cy="92.2" rx="1.1" ry="0.8" fill="#394848"/> <circle cx="81.1" cy="92.2" r="0.8" fill="#a2b2b3"/> </g> <g id="wheel-3" data-name="wheel"> <circle cx="76.7" cy="96.5" r="2.9" fill="#a2b2b3"/> <circle cx="76.7" cy="96.5" r="2" fill="#ddeced"/> <ellipse cx="76.4" cy="96.5" rx="1.1" ry="0.8" fill="#394848"/> <circle cx="76.8" cy="96.5" r="0.8" fill="#a2b2b3"/> </g> <g id="wheel-4" data-name="wheel"> <circle cx="88.9" cy="95.2" r="4.1" fill="#a2b2b3"/> <circle cx="88.9" cy="95.2" r="2.8" fill="#ddeced"/> <ellipse cx="88.5" cy="95.2" rx="1.6" ry="1.1" fill="#394848"/> <circle cx="89" cy="95.2" r="1.1" fill="#a2b2b3"/> </g> </g> <g id="leftarm"> <g id="bicep"> <path d="M165.2,998.3H151.2a3.5,3.5,0,0,0-2.7,4.2c.4,2.3,4.4,2.4,4.4,2.4l11.9-.3s4.2.8,3.9-2.8A3.5,3.5,0,0,0,165.2,998.3Z" transform="translate(-81.8 -924.4)" fill="#f2791e"/> <path d="M154.1,998.4h12.7s2.2.2,2.2,3.1c0,0,.3,2.8-1.8,3s-13.1.3-13.1.3Z" transform="translate(-81.8 -924.4)" fill="#ddeced"/> <path fill="#636767" d="M72.3 78L75.9 73.8 78.5 73.9 73.5 80.2 72.3 80.2 72.3 78z"/> <path fill="#636767" d="M76 80.2L81.4 73.9 84 73.9 79 80.1 76 80.2z"/> <path d="M163.9,1004.5l4.3-5.4a2.6,2.6,0,0,1,.6,1.9l-2.8,3.5Z" transform="translate(-81.8 -924.4)" fill="#636767"/> </g> <g clip-path="url(#clip-path-5)"> <path id="newleftarm" d="M150.1,1000.7s-1.8-.3-2,.9,1.8,1,1.8,1l17-.2s1.1-.7.3-1.5S150.1,1000.7,150.1,1000.7Z" transform="translate(-81.8 -924.4)" fill="#a2b2b3"/> </g> <g id="hand"> <ellipse cx="66.8" cy="77.3" rx="0.9" ry="0.9" fill="#636767"/> <path d="M146.1,998.7l4.5,4.9a.8.8,0,0,1-.3,1.1l-3.5,2.1s-.5,0-.4.8,1,1.5.1,2-5.7-2.6-5.7-2.6l-2-4.5a1.7,1.7,0,0,1,1.3-2Z" transform="translate(-81.8 -924.4)" fill="#a2b2b3"/> <path d="M147.2,1001.1l-4.3,1.1a1.6,1.6,0,0,0-1.1,2.1c.3,1.2,1,3.2,1,3.2" transform="translate(-81.8 -924.4)" fill="none" stroke="#636767" stroke-linecap="round" stroke-miterlimit="10" stroke-width="0.5" opacity="0.46"/> </g> </g> </g> </g> </svg> </div>
CSS代码
body { width: 100vw; height: 100vh; overflow: hidden; font-family: 'Montserrat', sans-serif; background: #23a9e0; cursor: url('https://s3-us-west-2.amazonaws.com/s.cdpn.io/28963/cockroach%20(2).ico'), default; -webkit-overflow-scrolling: touch; } #app { -webkit-tap-highlight-color: transparent; } svg { width: 100vw; height: 100vh; max-height: 400px; margin-left: 20vw; } p { font-size: 16px; color: white; text-align: center; } .isFlipped { transform: scaleX(-1); transform-origin: 50% 50%; } #leftarm { transform-origin: 100% 0; } @media screen and (max-width: 600px) { svg { max-height: 200px !important; margin-left: 0 !important; } }
JavaScript代码
new Vue({ el: '#app', data() { return { startX: 0, x: 0, y: 0, flip: false, audioPlay: false, startArms: 0 } }, methods: { armsTL() { let tl = new TimelineMax(); tl.add('startarms') tl.to('#backhand', 2, { x: -16, rotation: 150, transformOrigin: '50% 50%' }, 'startarms'); tl.to('#rightarm', 2, { rotation: 30, transformOrigin: '100% 0' }, 'startarms'); tl.to('#newrightarm', 2, { x: -94, y: -918, rotation: 10, transformOrigin: '100% 100%' }, 'startarms'); tl.to('#hand', 2, { x: -15, y: -7, rotation: 90, transformOrigin: '50% 50%' }, 'startarms'); tl.to('#leftarm', 2, { rotation: 20, transformOrigin: '100% 0' }, 'startarms'); tl.to('#newleftarm', 2, { x: -100, y: -924, transformOrigin: '100% 100%' }, 'startarms'); return tl; }, coordinates(e) { const audio = new Audio('https://s3-us-west-2.amazonaws.com/s.cdpn.io/28963/Whoa.mp3'), walleBox = document.getElementById('walle').getBoundingClientRect(), walleCoords = walleBox.width / 2 + walleBox.left; if (this.startArms == 0) { this.startArms = this.armsTL(); } this.y = e.clientY / 80 - 2; if (e.clientX > walleCoords) { this.x = -(e.clientX / 200); this.flip = true; if (this.audioPlay === false) { audio.play(); this.audioPlay = true; } } else { this.audioPlay = false; this.x = e.clientX / 200 - 5; this.flip = false; TweenMax.set("#righteyeb2", { scaleX: 1 + (1 - e.clientX / walleCoords) / 5 }); TweenMax.set("#lefteyeb2", { scaleX: 1 + (1 - e.clientX / walleCoords) / 5 }); TweenMax.set("#walle", { x: ((e.clientX / walleCoords) * 50) - 40 }); this.startArms.progress(1 - (e.clientX / walleCoords)).pause(); } }, }, mounted() { let tl = new TimelineMax({ repeat: -1, repeatDelay: 2 }); tl.add('redo') tl.to('#lefteye', 0.5, { rotation: 5, repeat: 3, yoyo: true, transformOrigin: '100% 50%', ease: Sine.easeOut }, 'redo'); tl.to('#righteye', 0.5, { rotation: -5, repeat: 3, yoyo: true, transformOrigin: '0% 30%', ease: Sine.easeOut }, 'redo+=0'); tl.fromTo('#lefteyeball', 0.05, { scaleY: 1 }, { scaleY: 0, repeat: 3, yoyo: true, transformOrigin: '50% 50%', ease: Circ.easeOut }, 'redo+=4'); tl.fromTo('#righteyeball', 0.05, { scaleY: 1 }, { scaleY: 0, repeat: 3, yoyo: true, transformOrigin: '50% 50%', ease: Circ.easeOut }, 'redo+=4'); tl.to('#eyecontain', 0.4, { rotation: -15, repeat: 1, yoyo: true, transformOrigin: '50% 50%', ease: Sine.easeInOut }, 'redo+=2'); } }); TweenMax.to('p', 0.5, { opacity: 0, delay: 2, ease: Sine.easeIn });
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!