likeFx.vue 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. <template>
  2. <view class="">
  3. <canvas :style="'width:' + width + 'px;height:' + height + 'px'" canvas-id="bubble" class="like-fx"></canvas>
  4. </view>
  5. </template>
  6. <script>
  7. export default {
  8. name: 'LikeFx',
  9. data() {
  10. return {
  11. queue: {},
  12. ctx: null,
  13. timer: 0
  14. }
  15. },
  16. props: {
  17. height: {
  18. type: Number,
  19. default: 1920
  20. },
  21. width: {
  22. type: Number,
  23. default: 375
  24. }
  25. },
  26. mounted() {
  27. this.ctx = uni.createCanvasContext("bubble")
  28. this.queue = {}
  29. console.log('likeFx mounted');
  30. },
  31. destroyed() {
  32. console.log('likeFx destoryed');
  33. this.clearTimer()
  34. },
  35. methods: {
  36. /**点赞 */
  37. likeClick() {
  38. console.log('开始点赞啦');
  39. const image = "/static/img/likeFx/" + this.getRandomInt(1, 33) + ".png";
  40. const anmationData = {
  41. id: new Date().getTime(),
  42. timer: 0,
  43. opacity: 0,
  44. pathData: this.generatePathData(),
  45. image: image,
  46. factor: {
  47. // speed: 0.0009, // 运动速度,值越小越慢
  48. // t: 0.4// 贝塞尔函数系数,当为0,就是从无到有,这时候屏幕高度也要调一下
  49. speed: 0.0006, // 运动速度,值越小越慢
  50. t: 0.6 // 贝塞尔函数系数,当为0,就是从无到有,这时候屏幕高度也要调一下
  51. }
  52. };
  53. if (Object.keys(this.queue).length > 0) {
  54. this.queue[anmationData.id] = anmationData;
  55. } else {
  56. this.queue[anmationData.id] = anmationData;
  57. this.bubbleAnimate();
  58. }
  59. // console.log(image, this.queue);
  60. },
  61. /**获取最大最小随机值 */
  62. getRandom(min, max) {
  63. return Math.random() * (max - min) + min;
  64. },
  65. /**获取最大最小之前随机值的整数 */
  66. getRandomInt(min, max) {
  67. return Math.floor(Math.random() * (max - min + 1)) + min;
  68. },
  69. /**获取图片路径 */
  70. generatePathData() {
  71. let width = this.width,
  72. height = this.height;
  73. const p0 = {
  74. x: 0.72 * width,
  75. y: height
  76. };
  77. const p1 = {
  78. x: this.getRandom(0.22 * width, 0.33 * width),
  79. y: this.getRandom(0.5 * height, 0.75 * height)
  80. };
  81. const p2 = {
  82. x: this.getRandom(0, 0.88 * width),
  83. y: this.getRandom(0.25 * height, 0.5 * height)
  84. };
  85. const p3 = {
  86. x: this.getRandom(0, 0.88 * width),
  87. y: this.getRandom(0, 0.125 * height)
  88. };
  89. return [p0, p1, p2, p3];
  90. },
  91. /**更新图片的最新运动路径 */
  92. updatePath(data, factor) {
  93. const p0 = data[0];
  94. const p1 = data[1];
  95. const p2 = data[2];
  96. const p3 = data[3];
  97. const t = factor.t;
  98. /*计算多项式系数 (下同)*/
  99. const cx1 = 3 * (p1.x - p0.x);
  100. const bx1 = 3 * (p2.x - p1.x) - cx1;
  101. const ax1 = p3.x - p0.x - cx1 - bx1;
  102. const cy1 = 3 * (p1.y - p0.y);
  103. const by1 = 3 * (p2.y - p1.y) - cy1;
  104. const ay1 = p3.y - p0.y - cy1 - by1;
  105. const x = ax1 * (t * t * t) + bx1 * (t * t) + cx1 * t + p0.x;
  106. const y = ay1 * (t * t * t) + by1 * (t * t) + cy1 * t + p0.y;
  107. // console.log(data, x, y);
  108. return {
  109. x,
  110. y
  111. };
  112. },
  113. /**点赞动画 */
  114. bubbleAnimate() {
  115. let width = this.width,
  116. height = this.height;
  117. Object.keys(this.queue).forEach(key => {
  118. const anmationData = this.queue[+key];
  119. const {
  120. x,
  121. y
  122. } = this.updatePath(
  123. anmationData.pathData,
  124. anmationData.factor
  125. );
  126. const speed = anmationData.factor.speed;
  127. anmationData.factor.t += speed;
  128. var curWidth = 30;
  129. curWidth = (height - y) / 1.5;
  130. curWidth = Math.min(30, curWidth);
  131. var curAlpha = anmationData.opacity;
  132. curAlpha = y / (0.3 * height); //消失的高度适当调一下
  133. curAlpha = Math.min(1, curAlpha);
  134. this.ctx.globalAlpha = curAlpha;
  135. this.ctx.drawImage(anmationData.image, x - curWidth / 2, y, curWidth, curWidth);
  136. // this.ctx.setFillStyle('red')
  137. // this.ctx.fillRect(x - curWidth / 2, y, 50, 50)
  138. if (anmationData.factor.t > 1) {
  139. delete this.queue[anmationData.id];
  140. }
  141. if (y > height) {
  142. delete this.queue[anmationData.id];
  143. }
  144. });
  145. this.ctx.draw();
  146. if (Object.keys(this.queue).length > 0) {
  147. this.timer = setTimeout(() => {
  148. this.bubbleAnimate();
  149. }, 5);
  150. } else {
  151. this.clearTimer()
  152. this.ctx.draw(); // 清空画面
  153. }
  154. },
  155. clearTimer() {
  156. if (this.timer) {
  157. clearTimeout(this.timer)
  158. }
  159. }
  160. }
  161. }
  162. </script>
  163. <style lang="scss">
  164. .like-fx {
  165. position: fixed;
  166. right: 0;
  167. z-index: 1024;
  168. pointer-events: none;
  169. /* background-color: red; */
  170. }
  171. </style>