前端开发者丨JavaScript
在做小程序的项目中, 需要在添加购物车的时候, 增加抛物线小球动画。 先给大家看下效果图( 其实已经是实现后的效果了, 顺便给自己公司打广告了哈哈) 分析这种不固定起始位置的动画, 自然不能用 gif 图, 所以只能用原生代码实现那我们有什么工具来实现动画呢? 小程序提供了 js API createAnimation 来创建动画来创建动画 css transition工具有了, 我们再看一下什么是抛物线。 这里我们只讨论水平抛物线, 水平抛物线从数学原理上来说就是【 水平匀速、 垂直加速的运动】, 转换成代码层面就是在动画效果 timingFunction 中, 水平动画采用 linear, 垂直动画采用 ease – in所以我们需要把这个抛物线动画分解成 两个 同时 进行但 不同动画效果 的动画。 实现( 一) 小程序的实现js: cartAnimation(x, y) { // x y 为手指点击的坐标,即球的起始坐标 let self = this, cartY = app.globalData.winHeight – 50, // 结束位置(购物车图片)纵坐标 cartX = 50, // 结束位置(购物车图片)的横坐标 animationX = flyX(cartX, x), // 创建球的横向动画 animationY = flyY(cartY, y) // 创建球的纵向动画 this.setData({ ballX: x, ballY: y, showBall: true }) setTimeoutES6(100).then(() => { // 100 ms 延时,确保球已经到位并显示 self.setData({ animationX: animationX.export(), animationY: animationY.export(), }) return setTimeoutES6(400) // 400 ms 是球的抛物线动画时长 }).then(() => { // 400 ms 延时后隐藏球 this.setData({ showBall: false, }) }) } function setTimeoutES6(sec) { // Promise 化 setTimeout return new Promise((resolve, reject) => { setTimeout(() => {resolve()}, sec) }) } function flyX(cartX, oriX) { // 水平动画 let animation = wx.createAnimation({ duration: 400, timingFunction: ‘linear’, }) animation.left(cartX).step() return animation } function flyY(cartY, oriY) { // 垂直动画 let animation = wx.createAnimation({ duration: 400, timingFunction: ‘ease-in’, }) animation.top(cartY).step() return animation } 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 cartAnimation ( x , y ) { // x y 为手指点击的坐标,即球的起始坐标 let self = this , cartY = app . globalData . winHeight – 50 , // 结束位置(购物车图片)纵坐标 cartX = 50 , // 结束位置(购物车图片)的横坐标 animationX = flyX ( cartX , x ) , // 创建球的横向动画 animationY = flyY ( cartY , y ) // 创建球的纵向动画 this . setData ( { ballX : x , ballY : y , showBall : true } ) setTimeoutES6 ( 100 ) . then ( ( ) = > { // 100 ms 延时,确保球已经到位并显示 self . setData ( { animationX : animationX . export ( ) , animationY : animationY . export ( ) , } ) return setTimeoutES6 ( 400 ) // 400 ms 是球的抛物线动画时长 } ) . then ( ( ) = > { // 400 ms 延时后隐藏球 this . setData ( { showBall : false , } ) } ) } function setTimeoutES6 ( sec ) { // Promise 化 setTimeout return new Promise ( ( resolve , reject ) = > { setTimeout ( ( ) = > { resolve ( ) } , sec ) } ) } function flyX ( cartX , oriX ) { // 水平动画 let animation = wx . createAnimation ( { duration : 400 , timingFunction : ‘linear’ , } ) animation . left ( cartX ) . step ( ) return animation } function flyY ( cartY , oriY ) { // 垂直动画 let animation = wx . createAnimation ( { duration : 400 , timingFunction : ‘ease-in’ , } ) animation . top ( cartY ) . step ( ) return animation }html:<view animation=”{{animationY}}” style=”position:fixed;top:{{ballY}}px;” hidden=”{{!showBall}}”> <view class=”ball” animation=”{{animationX}}” style=”position:fixed;left:{{ballX}}px;”/> </view> 1 2 3 < view animation = “{{animationY}}” style = “position:fixed;top:{{ballY}}px;” hidden = “{{!showBall}}” > < view class = “ball” animation = “{{animationX}}” style = “position:fixed;left:{{ballX}}px;” / > < / view >translate 优化据我所知,用 transform: translate() 来实现的动画会比 top & left 性能更优,但实现下来却没那么容易咯。研究来研究去,发现 translate 的做法比 top & left 的做法多了一步,就是需要将小球的 translate 位移还原(否则 translate 一直有值),才能保证下一次的位移从点击的位置开始cartAnimation(x, y) { let self = this, cartY = app.globalData.winHeight – 50, cartX = 50, animationX = flyX(cartX, x), animationY = flyY(cartY, y) this.setData({ leftNum: x, topNum: y, showBall: true }) setTimeoutES6(100).then(() => { self.setData({ animationDataX: animationX.export(), animationDataY: animationY.export(), }) return setTimeoutES6(400) }).then(() => { this.setData({ showBall: false, animationX: flyX(0, 0, 0).export(), // 还原小球位置,即 translate 恢复默认值 animationY: flyY(0, 0, 0).export(), }) }) } function flyX(cartX,oriX,duration) { let animation = wx.createAnimation({ duration: duration||400, timingFunction: ‘linear’, }) animation.translateX(cartX-oriX).step() return animation } function flyY(cartY,oriY,duration) { let animation = wx.createAnimation({ duration: duration||400, timingFunction: ‘ease-in’, }) animation.translateY(cartY-oriY).step() return animation } 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 cartAnimation ( x , y ) { let self = this , cartY = app . globalData . winHeight – 50 , cartX = 50 , animationX = flyX ( cartX , x ) , animationY = flyY ( cartY , y ) this . setData ( { leftNum : x , topNum : y , showBall : true } ) setTimeoutES6 ( 100 ) . then ( ( ) = > { self . setData ( { animationDataX : animationX . export ( ) , animationDataY : animationY . export ( ) , } ) return setTimeoutES6 ( 400 ) } ) . then ( ( ) = > { this . setData ( { showBall : false , animationX : flyX ( 0 , 0 , 0 ) . export ( ) , // 还原小球位置,即 translate 恢复默认值 animationY : flyY ( 0 , 0 , 0 ) . export ( ) , } ) } ) } function flyX ( cartX , oriX , duration ) { let animation = wx . createAnimation ( { duration : duration || 400 , timingFunction : ‘linear’ , } ) animation . translateX ( cartX – oriX ) . step ( ) return animation } function flyY ( cartY , oriY , duration ) { let animation = wx . createAnimation ( { duration : duration || 400 , timingFunction : ‘ease-in’ , } ) animation . translateY ( cartY – oriY ) . step ( ) return animation }html 部分不变(二)H5 的实现除了小程序之外,前端日常开发更多的当然还是 H5,下面我将用 CSS3 transition 的方法来实现<!DOCTYPE html> <html lang=”en” style=”width:100%;height:100%;”> <head> <meta charset=”UTF-8″> <meta name=”viewport” content=”width=device-width”> <style> * { padding: 0; margin: 0; } #ball { width:12px; height:12px; background: #5EA345; border-radius: 50%; position: fixed; transition: left 1s linear, top 1s ease-in; } </style> <title>CSS3 水平抛物线动画</title> </head> <body style=”width:100%;height:100%;”> <div id=”ball”></div> </body> <script> var $ball = document.getElementById(‘ball’); document.body.onclick = function (evt) { console.log(evt.pageX,evt.pageY) $ball.style.top = evt.pageY+’px’; $ball.style.left = evt.pageX+’px’; $ball.style.transition = ‘left 0s, top 0s’; setTimeout(()=>{ $ball.style.top = window.innerHeight+’px’; $ball.style.left = ‘0px’; $ball.style.transition = ‘left 1s linear, top 1s ease-in’; }, 20) } </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 < ! DOCTYPE html > < html lang = “en” style = “width:100%;height:100%;” > < head > < meta charset = “UTF-8” > < meta name = “viewport” content = “width=device-width” > <style> * { padding : 0 ; margin : 0 ; } #ball { width : 12px ; height : 12px ; background : #5EA345 ; border-radius : 50% ; position : fixed ; transition : left 1s linear, top 1s ease-in ; } </style> < title > CSS3 水平抛物线动画 < / title > < / head > < body style = “width:100%;height:100%;” > < div id = “ball” > < / div > < / body > <script> var $ ball = document . getElementById ( ‘ball’ ) ; document . body . onclick = function ( evt ) { console . log ( evt . pageX , evt . pageY ) $ ball . style . top = evt . pageY + ‘px’ ; $ ball . style . left = evt . pageX + ‘px’ ; $ ball . style . transition = ‘left 0s, top 0s’ ; setTimeout ( ( ) = > { $ ball . style . top = window . innerHeight + ‘px’ ; $ ball . style . left = ‘0px’ ; $ ball . style . transition = ‘left 1s linear, top 1s ease-in’ ; } , 20 ) } </script> < / html >
}
前端开发者丨JavaScript
评论前必须登录!
注册