当前位置:   article > 正文

微信小程序使用wxs实现购物车贝塞尔曲线_小程序贝塞尔曲线广告

小程序贝塞尔曲线广告

基本实现思路

小程序要实现点击加购时绘制一个抛物线动画,这个抛物线动画是计算出来的贝塞尔曲线上每个点的坐标,然后通过`setData`动态给元素设置样式,从而实现动画的效果,但是频繁的调用`setData`会造成一定的性能问题,这里采用微信官方提供的`wxs`

wxs实现

  1. <!-- 自定义动画 -->
  2. <wxs module="customAnimate">
  3. var curIndex = 0
  4. var ballIns
  5. var Ins
  6. var curCoordIdx
  7. var wxsFunction = function(event, ownerInstance) {
  8. var ins = ownerInstance;
  9. var topPoint = { x: 0, y: 0 }
  10. // 起点
  11. var finger = { x: event.detail.x, y: event.detail.y }
  12. var cartIconInstance = ownerInstance.selectComponent('.cart-icon')
  13. // 终点
  14. var busPos = { x: cartIconInstance.getBoundingClientRect().x, y: cartIconInstance.getBoundingClientRect().y }
  15. console.log('开始动画')
  16. if (finger['y'] < busPos['y']) {
  17. topPoint['y'] = finger['y'] - 80;
  18. } else {
  19. topPoint['y'] = busPos['y'] - 80;
  20. }
  21. topPoint['x'] = Math.abs(finger['x'] - busPos['x']) / 2;
  22. if (finger['x'] > busPos['x']) {
  23. topPoint['x'] = (finger['x'] - busPos['x']) / 2 + busPos['x'];
  24. } else {
  25. topPoint['x'] = (busPos['x'] - finger['x']) / 2 + finger['x'];
  26. }
  27. var linePos = bezier([busPos, topPoint, finger], 30)
  28. coordArr = linePos.bezier_points
  29. executeCartAnimation()
  30. function executeCartAnimation () {
  31. curCoordIdx = coordArr.length - 1
  32. // 使用 requestAnimationFrame 代替定时器
  33. ins.requestAnimationFrame(setStyleByFrame)
  34. }
  35. function setStyleByFrame() {
  36. if (curCoordIdx >= 0) {
  37. var scale = 0.6
  38. if (curCoordIdx > 20) {
  39. scale = curCoordIdx / coordArr.length
  40. }
  41. ins.selectComponent('.good_box').setStyle({
  42. display: 'block',
  43. left: coordArr[curCoordIdx].x + 'px',
  44. top: coordArr[curCoordIdx].y + 'px',
  45. transform: 'scale('+ scale +')'
  46. })
  47. console.log(curCoordIdx, coordArr.length)
  48. curCoordIdx -= 1
  49. ins.requestAnimationFrame(setStyleByFrame)
  50. } else {
  51. ins.selectComponent('.good_box').setStyle({
  52. display: 'none'
  53. })
  54. }
  55. }
  56. }
  57. function bezier(points, times) {
  58. // 0、以3个控制点为例,点A,B,C,AB上设置点D,BC上设置点E,DE连线上设置点F,则最终的贝塞尔曲线是点F的坐标轨迹。
  59. // 1、计算相邻控制点间距。
  60. // 2、根据完成时间,计算每次执行时D在AB方向上移动的距离,E在BC方向上移动的距离。
  61. // 3、时间每递增100ms,则D,E在指定方向上发生位移, F在DE上的位移则可通过AD/AB = DF/DE得出。
  62. // 4、根据DE的正余弦值和DE的值计算出F的坐标。
  63. // 邻控制AB点间距
  64. var bezier_points = [];
  65. var points_D = [];
  66. var points_E = [];
  67. var DIST_AB = Math.sqrt(Math.pow(points[1]['x'] - points[0]['x'], 2) + Math.pow(points[1]['y'] - points[0]['y'], 2));
  68. // 邻控制BC点间距
  69. var DIST_BC = Math.sqrt(Math.pow(points[2]['x'] - points[1]['x'], 2) + Math.pow(points[2]['y'] - points[1]['y'], 2));
  70. // D每次在AB方向上移动的距离
  71. var EACH_MOVE_AD = DIST_AB / times;
  72. // E每次在BC方向上移动的距离
  73. var EACH_MOVE_BE = DIST_BC / times;
  74. // 点AB的正切
  75. var TAN_AB = (points[1]['y'] - points[0]['y']) / (points[1]['x'] - points[0]['x']);
  76. // 点BC的正切
  77. var TAN_BC = (points[2]['y'] - points[1]['y']) / (points[2]['x'] - points[1]['x']);
  78. // 点AB的弧度值
  79. var RADIUS_AB = Math.atan(TAN_AB);
  80. // 点BC的弧度值
  81. var RADIUS_BC = Math.atan(TAN_BC);
  82. // 每次执行
  83. for (var i = 1; i <= times; i++) {
  84. // AD的距离
  85. var dist_AD = EACH_MOVE_AD * i;
  86. // BE的距离
  87. var dist_BE = EACH_MOVE_BE * i;
  88. // D点的坐标
  89. var point_D = {};
  90. point_D['x'] = dist_AD * Math.cos(RADIUS_AB) + points[0]['x'];
  91. point_D['y'] = dist_AD * Math.sin(RADIUS_AB) + points[0]['y'];
  92. points_D.push(point_D);
  93. // E点的坐标
  94. var point_E = {};
  95. point_E['x'] = dist_BE * Math.cos(RADIUS_BC) + points[1]['x'];
  96. point_E['y'] = dist_BE * Math.sin(RADIUS_BC) + points[1]['y'];
  97. points_E.push(point_E);
  98. // 此时线段DE的正切值
  99. var tan_DE = (point_E['y'] - point_D['y']) / (point_E['x'] - point_D['x']);
  100. // tan_DE的弧度值
  101. var radius_DE = Math.atan(tan_DE);
  102. // 地市DE的间距
  103. var dist_DE = Math.sqrt(Math.pow((point_E['x'] - point_D['x']), 2) + Math.pow((point_E['y'] - point_D['y']), 2));
  104. // 此时DF的距离
  105. var dist_DF = (dist_AD / DIST_AB) * dist_DE;
  106. // 此时DF点的坐标
  107. var point_F = {};
  108. point_F['x'] = dist_DF * Math.cos(radius_DE) + point_D['x'];
  109. point_F['y'] = dist_DF * Math.sin(radius_DE) + point_D['y'];
  110. bezier_points.push(point_F);
  111. }
  112. return {
  113. 'bezier_points': bezier_points
  114. };
  115. }
  116. module.exports = {
  117. wxsFunction: wxsFunction
  118. }
  119. </wxs>
<view catchtap="{{customAnimate.wxsFunction}}"></view>

与基本实现思路一致,不同的这里用`wxs`的高性能优势替代`setData`, 需要注意的是:wxs并不支持es6,不支持`setInterval`和`setTimeOut`,这里使用`requestAnimationFrame`这个api替代

最终测试测试在安卓端运行非常流畅,ios端表现不如安卓

最后附上微信官方文档 小程序框架 / 视图层 / 事件系统 / WXS 响应事件 (qq.com)

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/526538
推荐阅读
相关标签
  

闽ICP备14008679号