hx-jump-ball - ╕▒▒╛.vue 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. <template>
  2. <view class="hx-jump-ball">
  3. <view class="ballBox" :animation="ballBoxAnimationData" :style="{'z-index':index}">
  4. <view class="ballOuter"
  5. :animation="ballOuterAnimationData"
  6. :style="{width:ballWidth*2 + 'upx',height:ballHeight*2 + 'upx','background-color':backgroundColor,'background-image': backgroundImage ?`url(${backgroundImage})`: ''}">
  7. </view>
  8. </view>
  9. </view>
  10. </template>
  11. <script>
  12. export default {
  13. name: "hx-jump-ball",
  14. data() {
  15. return {
  16. flag: false,
  17. ballBoxAnimation: null,
  18. ballOuterAnimation: null,
  19. ballBoxAnimationData: {},
  20. ballOuterAnimationData: {},
  21. };
  22. },
  23. props: {
  24. //小球宽度
  25. ballWidth: {
  26. type: Number,
  27. default: 15
  28. },
  29. //小球高度
  30. ballHeight: {
  31. type: Number,
  32. default: 15
  33. },
  34. //小球颜色
  35. backgroundColor: {
  36. type: String,
  37. default: "reg"
  38. },
  39. //图片
  40. backgroundImage: {
  41. type: String,
  42. default: ""
  43. },
  44. //小球的堆叠顺序
  45. index: {
  46. type: Number,
  47. default: 0
  48. },
  49. //开始动画
  50. start: {
  51. type: Number,
  52. default: 1
  53. },
  54. //html元素class名称,[起点元素,终点元素]
  55. element:{
  56. type: Array,
  57. default(){
  58. return []
  59. }
  60. },
  61. //下落速度 ms毫秒
  62. speed:{
  63. type: Number,
  64. default: 800
  65. },
  66. //贝塞尔曲线
  67. bezier:{
  68. type: String,
  69. default: "cubic-bezier(.6,-0.63,.94,.71)"
  70. }
  71. },
  72. watch:{
  73. start(val,oldVal) {
  74. var that = this;
  75. if(!that.element){
  76. return;
  77. }
  78. if(this.flag){
  79. return;
  80. }
  81. that.flag = !that.flag;
  82. that.getElementCoordinate(that.element[0],that.element[1]);
  83. }
  84. },
  85. created() {
  86. this.ballBoxAnimation = uni.createAnimation({
  87. duration: 0,
  88. timingFunction: this.bezier,
  89. delay: 0
  90. });
  91. this.ballOuterAnimation = uni.createAnimation({
  92. duration: 0,
  93. timingFunction: "linear",
  94. delay: 0
  95. });
  96. this.setEnd();
  97. //初始化位置
  98. },
  99. methods:{
  100. //获取元素坐标
  101. getElementCoordinate(startElement,endElement){
  102. let that = this;
  103. const query = uni.createSelectorQuery();
  104. let nodesRef = query.select(startElement);
  105. nodesRef.fields({
  106. id: true,
  107. rect: true,
  108. size: true
  109. }, res => {
  110. if(!res){
  111. that.flag = !that.flag;
  112. that.$emit("msg",{code: 100, error: '未获取到起始元素位置'})
  113. return ;
  114. }
  115. const SLeft = res.left + ((res.width + that.ballWidth ) / 2 - that.ballWidth);
  116. const STop = res.bottom - ((res.height - that.ballHeight ) / 2 + that.ballHeight);
  117. let nodesRef2 = uni.createSelectorQuery().select(endElement);
  118. nodesRef2.fields({
  119. id: true,
  120. rect: true,
  121. size: true
  122. }, res2 => {
  123. if(!res2){
  124. that.$emit("msg",{code: 101, error: '未获取到结束元素位置'})
  125. return ;
  126. }
  127. //计算出元素的中心坐标
  128. let ELeft = res2.left + ((res2.width + that.ballWidth ) / 2 - that.ballWidth);
  129. let ETop = res2.bottom - ((res2.height - that.ballHeight ) / 2 + that.ballHeight);
  130. that.startAnimation(SLeft,STop,ELeft,ETop);
  131. }).exec()
  132. }).exec()
  133. },
  134. //开始动画
  135. startAnimation(SLeft,STop,ELeft,ETop){
  136. let that = this;
  137. let jumpDistance = SLeft - ELeft;
  138. // 暂时注释掉,待uniapp修复bug后再调整
  139. //根坐标
  140. // this.ballBoxAnimation.translate3d(ELeft,STop,0).step({duration: 800});
  141. // this.ballBoxAnimation.translate3d(ELeft,ETop,0).step({duration: 800});
  142. // this.ballBoxAnimationData = this.ballBoxAnimation.export();
  143. // console.log('根坐标执行玩');
  144. // //相对根的坐标
  145. // this.ballOuterAnimation.translate3d(jumpDistance,0,0).step({duration: 800});
  146. // this.ballOuterAnimation.translate3d(0,0,0).step({duration: 800});
  147. // this.ballOuterAnimationData = this.ballOuterAnimation.export();
  148. // console.log('相对根的坐标');
  149. // setTimeout(function() {
  150. // console.log("动画完成");
  151. // that.flag = !that.flag;
  152. // }, 800);
  153. //初始化位置
  154. //that.setStart(SLeft,STop,ELeft,ETop);
  155. //因为uniapp step()有bug,所以必须要延时执行
  156. that.ballBoxAnimation = uni.createAnimation({
  157. duration: 0,
  158. timingFunction: that.bezier,
  159. delay: 0
  160. });
  161. that.ballOuterAnimation = uni.createAnimation({
  162. duration: 0,
  163. timingFunction: "linear",
  164. delay: 0
  165. });
  166. //根坐标
  167. that.ballBoxAnimation.translate3d(ELeft,STop,0).opacity(1).step({duration: 0});
  168. that.ballBoxAnimation.opacity(1).translate3d(ELeft,ETop,0).step({duration: that.speed});
  169. that.ballBoxAnimation.opacity(0).step({duration: 0});
  170. that.ballBoxAnimationData = that.ballBoxAnimation.export();
  171. //相对根的坐标
  172. that.ballOuterAnimation.translate3d(SLeft - ELeft,0,0).opacity(1).step({duration: 0});
  173. that.ballOuterAnimation.opacity(1).translate3d(0,0,0).step({duration: that.speed});
  174. that.ballOuterAnimation.opacity(0).step({duration: 0});
  175. that.ballOuterAnimationData = that.ballOuterAnimation.export();
  176. setTimeout(function() {
  177. that.flag = !that.flag;
  178. that.$emit("msg",{code:0,status:true});
  179. }, that.speed);
  180. },
  181. //动画开始前初始化小球位置并显示小球
  182. setStart(SLeft,STop,ELeft,ETop){
  183. this.ballBoxAnimation.translate3d(ELeft,STop,0).opacity(1).step({duration: 0});
  184. this.ballBoxAnimationData = this.ballBoxAnimation.export();
  185. this.ballOuterAnimation.translate3d(SLeft - ELeft,0,0).opacity(1).step({duration: 0});
  186. this.ballOuterAnimationData = this.ballOuterAnimation.export();
  187. },
  188. //隐藏小球
  189. setEnd(){
  190. this.ballBoxAnimation.opacity(0).step({duration: 0});
  191. this.ballBoxAnimationData = this.ballBoxAnimation.export();
  192. this.ballOuterAnimation.opacity(0).step({duration: 0});
  193. this.ballOuterAnimationData = this.ballOuterAnimation.export();
  194. }
  195. }
  196. }
  197. </script>
  198. <style>
  199. .ballBox{
  200. position: fixed;
  201. left: 0;
  202. top: 0;
  203. z-index: 9;
  204. /* 用颜色来演示用原理 */
  205. /*background-color: #4CD964*/;
  206. height:30rpx;
  207. width:30rpx;
  208. }
  209. .ballOuter {
  210. background:red;
  211. height:100%;
  212. width:100%;
  213. border-radius: 50%;
  214. background-size: 100% 100%;
  215. background-position: center;
  216. }
  217. </style>