uni-cart-animation.vue 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. <template>
  2. <!-- 加入购物车动画 -->
  3. <view>
  4. <view class="good_box" v-show="!hide_good_box" :style="[{left:bus_x+'px', top:bus_y+'px', background:PrimaryColor}]"></view>
  5. </view>
  6. </template>
  7. <script>
  8. export default {
  9. data() {
  10. return {
  11. PrimaryColor: '#fe461d', // 背景色
  12. hide_good_box: true,
  13. bus_x:0,
  14. bus_y:0,
  15. }
  16. },
  17. created(e) {
  18. // 默认掉落坐标
  19. this.busPos = {};
  20. this.busPos['x'] = uni.getSystemInfoSync().windowWidth - 140;
  21. this.busPos['y'] = uni.getSystemInfoSync().windowHeight + 100;
  22. },
  23. methods:{
  24. //点击商品触发的事件
  25. touchOnGoods: function(e,busPos) {
  26. console.log(e, '进入动画')
  27. if(busPos){//是否自定义掉落坐标
  28. this.busPos = busPos
  29. }
  30. // 如果good_box正在运动
  31. if (!this.hide_good_box) return;
  32. this.finger = {};
  33. var topPoint = {};
  34. var flag = false; //false:倒序,true:正序
  35. this.finger["x"] = e.detail.clientX || e.touches[0].clientX; //点击的位置
  36. this.finger["y"] = e.detail.clientY || e.touches[0].clientY;
  37. if (this.finger['y'] < this.busPos['y']) {
  38. topPoint['y'] = this.finger['y'] - 150;
  39. } else {
  40. topPoint['y'] = this.busPos['y'] - 150;
  41. }
  42. topPoint['x'] = Math.abs(this.finger['x'] - this.busPos['x']) / 2;
  43. if (this.finger['x'] > this.busPos['x']) {
  44. topPoint['x'] = (this.finger['x'] - this.busPos['x']) / 2 + this.busPos['x'];
  45. console.log("0123")
  46. this.linePos = this.bezier([this.busPos, topPoint, this.finger], 30);
  47. flag = false
  48. } else { //
  49. topPoint['x'] = (this.busPos['x'] - this.finger['x']) / 2 + this.finger['x'];
  50. console.log("123")
  51. this.linePos = this.bezier([this.finger, topPoint, this.busPos], 30);
  52. flag = true
  53. }
  54. this.startAnimation(flag);
  55. },
  56. //开始动画
  57. startAnimation: function(flag) {
  58. // uni.vibrateShort(); //震动方法
  59. var that = this,
  60. bezier_points = that.linePos['bezier_points'],
  61. index = bezier_points.length;
  62. console.log(bezier_points, 'bezier_points')
  63. this.hide_good_box = false,
  64. this.bus_x = that.finger['x']
  65. this.bus_y = that.finger['y']
  66. if (!flag) {
  67. index = bezier_points.length;
  68. this.timer = setInterval(function() {
  69. index--;
  70. that.bus_x = bezier_points[index]['x']
  71. that.bus_y = bezier_points[index]['y']
  72. if (index <= 1) {
  73. clearInterval(that.timer);
  74. that.hide_good_box = true
  75. that.$emit('animationfinish')
  76. }
  77. }, 22);
  78. } else {
  79. index = 0;
  80. this.timer = setInterval(function() {
  81. index++;
  82. that.bus_x = bezier_points[index]['x']
  83. that.bus_y = bezier_points[index]['y']
  84. if (index >= 28) {
  85. clearInterval(that.timer);
  86. that.hide_good_box = true
  87. that.$emit('animationfinish')
  88. }
  89. }, 22);
  90. }
  91. },
  92. bezier: function(points, times) {
  93. // 0、以3个控制点为例,点A,B,C,AB上设置点D,BC上设置点E,DE连线上设置点F,则最终的贝塞尔曲线是点F的坐标轨迹。
  94. // 1、计算相邻控制点间距。
  95. // 2、根据完成时间,计算每次执行时D在AB方向上移动的距离,E在BC方向上移动的距离。
  96. // 3、时间每递增100ms,则D,E在指定方向上发生位移, F在DE上的位移则可通过AD/AB = DF/DE得出。
  97. // 4、根据DE的正余弦值和DE的值计算出F的坐标。
  98. // 邻控制AB点间距
  99. var bezier_points = [];
  100. var points_D = [];
  101. var points_E = [];
  102. const DIST_AB = Math.sqrt(Math.pow(points[1]['x'] - points[0]['x'], 2) + Math.pow(points[1]['y'] - points[0]['y'], 2));
  103. // 邻控制BC点间距
  104. const DIST_BC = Math.sqrt(Math.pow(points[2]['x'] - points[1]['x'], 2) + Math.pow(points[2]['y'] - points[1]['y'], 2));
  105. // D每次在AB方向上移动的距离
  106. const EACH_MOVE_AD = DIST_AB / times;
  107. // E每次在BC方向上移动的距离
  108. const EACH_MOVE_BE = DIST_BC / times;
  109. // 点AB的正切
  110. const TAN_AB = (points[1]['y'] - points[0]['y']) / (points[1]['x'] - points[0]['x']);
  111. // 点BC的正切
  112. const TAN_BC = (points[2]['y'] - points[1]['y']) / (points[2]['x'] - points[1]['x']);
  113. // 点AB的弧度值
  114. const RADIUS_AB = Math.atan(TAN_AB);
  115. // 点BC的弧度值
  116. const RADIUS_BC = Math.atan(TAN_BC);
  117. // 每次执行
  118. for (var i = 1; i <= times; i++) {
  119. // AD的距离
  120. var dist_AD = EACH_MOVE_AD * i;
  121. // BE的距离
  122. var dist_BE = EACH_MOVE_BE * i;
  123. // D点的坐标
  124. var point_D = {};
  125. point_D['x'] = dist_AD * Math.cos(RADIUS_AB) + points[0]['x'];
  126. point_D['y'] = dist_AD * Math.sin(RADIUS_AB) + points[0]['y'];
  127. points_D.push(point_D);
  128. // E点的坐标
  129. var point_E = {};
  130. point_E['x'] = dist_BE * Math.cos(RADIUS_BC) + points[1]['x'];
  131. point_E['y'] = dist_BE * Math.sin(RADIUS_BC) + points[1]['y'];
  132. points_E.push(point_E);
  133. // 此时线段DE的正切值
  134. var tan_DE = (point_E['y'] - point_D['y']) / (point_E['x'] - point_D['x']);
  135. // tan_DE的弧度值
  136. var radius_DE = Math.atan(tan_DE);
  137. // 地市DE的间距
  138. var dist_DE = Math.sqrt(Math.pow((point_E['x'] - point_D['x']), 2) + Math.pow((point_E['y'] - point_D['y']), 2));
  139. // 此时DF的距离
  140. var dist_DF = (dist_AD / DIST_AB) * dist_DE;
  141. // 此时DF点的坐标
  142. var point_F = {};
  143. point_F['x'] = dist_DF * Math.cos(radius_DE) + point_D['x'];
  144. point_F['y'] = dist_DF * Math.sin(radius_DE) + point_D['y'];
  145. bezier_points.push(point_F);
  146. }
  147. return {
  148. 'bezier_points': bezier_points
  149. };
  150. },
  151. }
  152. }
  153. </script>
  154. <style lang="scss" scoped>
  155. .good_box {
  156. width: 20rpx;
  157. height: 20rpx;
  158. position: fixed;
  159. border-radius: 50%;
  160. overflow: hidden;
  161. left: 50%;
  162. top: 50%;
  163. z-index: +99;
  164. border: 1px solid #fff;
  165. background: red;
  166. }
  167. </style>