赞
踩
小程序要实现点击加购时绘制一个抛物线动画,这个抛物线动画是计算出来的贝塞尔曲线上每个点的坐标,然后通过`setData`动态给元素设置样式,从而实现动画的效果,但是频繁的调用`setData`会造成一定的性能问题,这里采用微信官方提供的`wxs`
- <!-- 自定义动画 -->
- <wxs module="customAnimate">
- var curIndex = 0
- var ballIns
- var Ins
- var curCoordIdx
- var wxsFunction = function(event, ownerInstance) {
- var ins = ownerInstance;
- var topPoint = { x: 0, y: 0 }
- // 起点
- var finger = { x: event.detail.x, y: event.detail.y }
- var cartIconInstance = ownerInstance.selectComponent('.cart-icon')
- // 终点
- var busPos = { x: cartIconInstance.getBoundingClientRect().x, y: cartIconInstance.getBoundingClientRect().y }
-
- console.log('开始动画')
-
- if (finger['y'] < busPos['y']) {
- topPoint['y'] = finger['y'] - 80;
- } else {
- topPoint['y'] = busPos['y'] - 80;
- }
-
- topPoint['x'] = Math.abs(finger['x'] - busPos['x']) / 2;
-
- if (finger['x'] > busPos['x']) {
- topPoint['x'] = (finger['x'] - busPos['x']) / 2 + busPos['x'];
- } else {
- topPoint['x'] = (busPos['x'] - finger['x']) / 2 + finger['x'];
- }
- var linePos = bezier([busPos, topPoint, finger], 30)
- coordArr = linePos.bezier_points
- executeCartAnimation()
-
- function executeCartAnimation () {
- curCoordIdx = coordArr.length - 1
- // 使用 requestAnimationFrame 代替定时器
- ins.requestAnimationFrame(setStyleByFrame)
- }
-
- function setStyleByFrame() {
- if (curCoordIdx >= 0) {
- var scale = 0.6
- if (curCoordIdx > 20) {
- scale = curCoordIdx / coordArr.length
- }
- ins.selectComponent('.good_box').setStyle({
- display: 'block',
- left: coordArr[curCoordIdx].x + 'px',
- top: coordArr[curCoordIdx].y + 'px',
- transform: 'scale('+ scale +')'
- })
- console.log(curCoordIdx, coordArr.length)
- curCoordIdx -= 1
- ins.requestAnimationFrame(setStyleByFrame)
- } else {
- ins.selectComponent('.good_box').setStyle({
- display: 'none'
- })
- }
- }
- }
-
-
- function bezier(points, times) {
- // 0、以3个控制点为例,点A,B,C,AB上设置点D,BC上设置点E,DE连线上设置点F,则最终的贝塞尔曲线是点F的坐标轨迹。
- // 1、计算相邻控制点间距。
- // 2、根据完成时间,计算每次执行时D在AB方向上移动的距离,E在BC方向上移动的距离。
- // 3、时间每递增100ms,则D,E在指定方向上发生位移, F在DE上的位移则可通过AD/AB = DF/DE得出。
- // 4、根据DE的正余弦值和DE的值计算出F的坐标。
- // 邻控制AB点间距
- var bezier_points = [];
- var points_D = [];
- var points_E = [];
- var DIST_AB = Math.sqrt(Math.pow(points[1]['x'] - points[0]['x'], 2) + Math.pow(points[1]['y'] - points[0]['y'], 2));
- // 邻控制BC点间距
- var DIST_BC = Math.sqrt(Math.pow(points[2]['x'] - points[1]['x'], 2) + Math.pow(points[2]['y'] - points[1]['y'], 2));
- // D每次在AB方向上移动的距离
- var EACH_MOVE_AD = DIST_AB / times;
- // E每次在BC方向上移动的距离
- var EACH_MOVE_BE = DIST_BC / times;
- // 点AB的正切
- var TAN_AB = (points[1]['y'] - points[0]['y']) / (points[1]['x'] - points[0]['x']);
- // 点BC的正切
- var TAN_BC = (points[2]['y'] - points[1]['y']) / (points[2]['x'] - points[1]['x']);
- // 点AB的弧度值
- var RADIUS_AB = Math.atan(TAN_AB);
- // 点BC的弧度值
- var RADIUS_BC = Math.atan(TAN_BC);
- // 每次执行
- for (var i = 1; i <= times; i++) {
- // AD的距离
- var dist_AD = EACH_MOVE_AD * i;
- // BE的距离
- var dist_BE = EACH_MOVE_BE * i;
- // D点的坐标
- var point_D = {};
- point_D['x'] = dist_AD * Math.cos(RADIUS_AB) + points[0]['x'];
- point_D['y'] = dist_AD * Math.sin(RADIUS_AB) + points[0]['y'];
- points_D.push(point_D);
- // E点的坐标
- var point_E = {};
- point_E['x'] = dist_BE * Math.cos(RADIUS_BC) + points[1]['x'];
- point_E['y'] = dist_BE * Math.sin(RADIUS_BC) + points[1]['y'];
- points_E.push(point_E);
- // 此时线段DE的正切值
- var tan_DE = (point_E['y'] - point_D['y']) / (point_E['x'] - point_D['x']);
- // tan_DE的弧度值
- var radius_DE = Math.atan(tan_DE);
- // 地市DE的间距
- var dist_DE = Math.sqrt(Math.pow((point_E['x'] - point_D['x']), 2) + Math.pow((point_E['y'] - point_D['y']), 2));
- // 此时DF的距离
- var dist_DF = (dist_AD / DIST_AB) * dist_DE;
- // 此时DF点的坐标
- var point_F = {};
- point_F['x'] = dist_DF * Math.cos(radius_DE) + point_D['x'];
- point_F['y'] = dist_DF * Math.sin(radius_DE) + point_D['y'];
- bezier_points.push(point_F);
- }
- return {
- 'bezier_points': bezier_points
- };
- }
- module.exports = {
- wxsFunction: wxsFunction
- }
- </wxs>
<view catchtap="{{customAnimate.wxsFunction}}"></view>
与基本实现思路一致,不同的这里用`wxs`的高性能优势替代`setData`, 需要注意的是:wxs并不支持es6,不支持`setInterval`和`setTimeOut`,这里使用`requestAnimationFrame`这个api替代
最终测试测试在安卓端运行非常流畅,ios端表现不如安卓
最后附上微信官方文档 小程序框架 / 视图层 / 事件系统 / WXS 响应事件 (qq.com)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。