1 <!DOCTYPE html> 2 <html lang="zh-cmn-Hans"> 3 <head> 4 <meta charset="UTF-8"> 5 <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> 6 <link rel="stylesheet" href="css/style.css"> 7 <title>购物车动画</title> 8 <style> 9 html,body { 10 margin: 0; 11 padding: 0; 12 background-color: rgba(0, 0, 0, .5); 13 -webkit-user-select: none; 14 width: 100%; 15 height: 100%; 16 } 17 18 .wrapper { 19 width: 100%; 20 height: 100%; 21 background:#fff; 22 position: relative; 23 } 24 .parabola-animation { 25 width: 100%; 26 } 27 28 .parabola-box-hor { 29 position: fixed; 30 z-index: 99; 31 top: 0; 32 left: 0; 33 -webkit-animation: parabola-hor-animation 1s ease-out 1; 34 animation: parabola-hor-animation 1s ease-out 1; 35 } 36 37 .parabola-box-hor.top { 38 -webkit-animation-timing-function: ease-in; 39 animation-timing-function: ease-in; 40 } 41 42 .parabola-box-ver { 43 position: fixed; 44 top: 50px; 45 left: 20px; 46 overflow: hidden; 47 width: 35px; 48 height: 35px; 49 -webkit-animation: parabola-ver-animation 1s ease-in 1; 50 animation: parabola-ver-animation 1s ease-in 1; 51 border-radius: 50%; 52 } 53 54 .parabola-box-ver.top { 55 -webkit-animation-timing-function: ease-out; 56 animation-timing-function: ease-out; 57 } 58 59 .parabola-box-ver > img { 60 width: 100%; 61 height: 100%; 62 vertical-align: middle; 63 } 64 65 </style> 66 </head> 67 <body> 68 <div class="wrapper"> 69 <div class="top" title="开始位置" style="30px;height:30px;background:yellow; position:absolute;left:100px;top:0;"></div> 70 <div class="bottom" title="结束位置" style="30px;height:30px;background:green;position:absolute;right:0;bottom:200px;"></div> 71 </div> 72 <script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script> 73 </body> 74 </html> 75 76 <script> 77 var addCar = function(opt) { 78 return (function() { 79 var parabola = function(opt) { 80 this.init(opt); 81 }; 82 parabola.prototype = {//原型,给原型添加方法:1.计算值;2.dom元素;3.坐标值; 83 init: function(opt) { 84 var flyO = this.calculatedValue(opt), 85 flyDom = this.creatHtml(flyO.site, flyO.img ,flyO.callback), 86 flyRule = this.creatRule(flyO.coord); 87 88 document.getElementsByTagName('head')[0].appendChild(flyRule); 89 document.body.appendChild(flyDom); 90 }, 91 creatRule: function(coord) { 92 var cssAnimation = document.createElement('style'); 93 cssAnimation.type = "text/css"; 94 var rules = " 95 @-webkit-keyframes parabola-hor-animation{ 96 0%{ 97 -webkit-transform: translate(0px, 0px); 98 transform: translate(0px, 0px); 99 } 100 10%{ 101 -webkit-transform: translate(0px, 0px); 102 transform: translate(0px, 0px); 103 } 104 100%{ 105 -webkit-transform: translate(" + coord.x + "px, 0px); 106 transform: translate(" + coord.x + "px, 0px); 107 } 108 } 109 @keyframes parabola-hor-animation{ 110 0%{ 111 -webkit-transform: translate(0px, 0px); 112 transform: translate(0px, 0px); 113 } 114 10%{ 115 -webkit-transform: translate(0px, 0px); 116 transform: translate(0px, 0px); 117 } 118 100%{ 119 -webkit-transform: translate(" + coord.x + "px, 0px); 120 transform: translate(" + coord.x + "px, 0px); 121 } 122 } 123 @-webkit-keyframes parabola-ver-animation{ 124 0%{ 125 -webkit-transform: translate(0px, 0px); 126 transform: translate(0px, 0px); 127 } 128 10%{ 129 -webkit-transform: translate(0px, " + coord.os + "px); 130 transform: translate(0px, " + coord.os + "px); 131 } 132 100%{ 133 -webkit-transform: translate(0px," + coord.y + "px); 134 transform: translate(0px," + coord.y + "px); 135 } 136 } 137 @keyframes parabola-ver-animation{ 138 0%{ 139 -webkit-transform: translate(0px, 0px); 140 transform: translate(0px, 0px); 141 } 142 10%{ 143 -webkit-transform: translate(0px, " + coord.os + "px); 144 transform: translate(0px, " + coord.os + "px); 145 } 146 100%{ 147 -webkit-transform: translate(0px," + coord.y + "px); 148 transform: translate(0px," + coord.y + "px); 149 } 150 } 151 "; 152 cssAnimation.innerHTML = rules; 153 return cssAnimation; 154 }, 155 creatHtml: function(site, img ,callback) { 156 var imgHtml = img == '' ? '' : '<img src="' + img + '">'; 157 158 var html = '<div class="parabola-box-hor"> 159 <div class="parabola-box-ver"> 160 ' + imgHtml + ' 161 </div> 162 </div>'; 163 164 var parentBox = document.createElement('div'); 165 parentBox.innerHTML = html; 166 parentBox.setAttribute('class', 'parabola-animation'); 167 168 $(parentBox).on('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', '.parabola-box-ver', function() { 169 var _pfly = $(parentBox); 170 if (_pfly.length) _pfly.remove(); 171 callback(); 172 }); 173 var frag = document.createDocumentFragment(); 174 frag.appendChild(parentBox); 175 176 var verBox = frag.querySelector('.parabola-box-ver'), 177 horBpx = frag.querySelector('.parabola-box-hor'); 178 verBox.style.left = site.left + 'px'; 179 verBox.style.top = site.top + 'px'; 180 181 if (site.cubic) { 182 verBox.setAttribute("class", 'parabola-box-ver top'); 183 horBpx.setAttribute("class", 'parabola-box-hor top'); 184 } 185 return frag; 186 }, 187 calculatedValue: function(opt) { 188 var fly = { 189 begin: '', 190 end: '', 191 img: '', 192 callback: function() { 193 console.log('动画完成'); 194 } 195 }, 196 vData = { 197 site: { 198 left: 0, 199 top: 0, 200 cubic: false 201 }, 202 img: '', 203 coord: { 204 x: 0, 205 y: 0, 206 os: 0 207 }, 208 callback: function() {} 209 }, 210 _this = this; 211 212 if (typeof opt == 'object') { 213 fly = $.extend(true, fly, opt); 214 } 215 216 //如果没有这两个元素中的其中一个则终止 217 if (!fly.begin.length || !fly.end.length) return vData; 218 /** 219 * beginCrood 获取开始元素的位置 220 * endCrood 获取结束元素的位置 221 */ 222 var beginCrood = fly.begin[0].getBoundingClientRect(), 223 endCrood = fly.end[0].getBoundingClientRect(); 224 225 /*! 226 * 购物车动画出现的位置 227 * left: 开始元素的left+width/2 228 * top: 开始元素的top 229 * 购物车动画结束的位置 230 * x: 结束元素的left+width/2 再减去购物车动画出现的位置的left 231 * y: 结束元素的top+height/2 再减去购物车动画出现的位置的top 232 */ 233 /** 234 * 全部减去 18是因为购物车宽度和高度都是35px;一半难得算(-_-),就填18 235 */ 236 vData.site.left = beginCrood.left + parseInt(beginCrood.width / 2, 10) - 18; 237 vData.site.top = beginCrood.top - 18; 238 vData.coord.x = endCrood.left + parseInt(endCrood.width / 2, 10) - vData.site.left - 18; 239 vData.coord.y = endCrood.top + parseInt(endCrood.height / 2, 10) - vData.site.top - 18; 240 vData.coord.os = -50; 241 vData.img = fly.img; 242 vData.callback = fly.callback; 243 if (beginCrood.top > endCrood.top) vData.site.cubic = true; 244 245 return vData; 246 } 247 } 248 return new parabola(opt); 249 })(); 250 } 251 var addCar = function(opt) { 252 return (function() { 253 var parabola = function(opt) { 254 this.init(opt); 255 }; 256 parabola.prototype = {//原型,给原型添加方法:1.计算值;2.dom元素;3.坐标值; 257 init: function(opt) { 258 var flyO = this.calculatedValue(opt), 259 flyDom = this.creatHtml(flyO.site, flyO.img ,flyO.callback), 260 flyRule = this.creatRule(flyO.coord); 261 262 document.getElementsByTagName('head')[0].appendChild(flyRule); 263 document.body.appendChild(flyDom); 264 }, 265 creatRule: function(coord) { 266 var cssAnimation = document.createElement('style'); 267 cssAnimation.type = "text/css"; 268 var rules = " 269 @-webkit-keyframes parabola-hor-animation{ 270 0%{ 271 -webkit-transform: translate(0px, 0px); 272 transform: translate(0px, 0px); 273 } 274 10%{ 275 -webkit-transform: translate(0px, 0px); 276 transform: translate(0px, 0px); 277 } 278 100%{ 279 -webkit-transform: translate(" + coord.x + "px, 0px); 280 transform: translate(" + coord.x + "px, 0px); 281 } 282 } 283 @keyframes parabola-hor-animation{ 284 0%{ 285 -webkit-transform: translate(0px, 0px); 286 transform: translate(0px, 0px); 287 } 288 10%{ 289 -webkit-transform: translate(0px, 0px); 290 transform: translate(0px, 0px); 291 } 292 100%{ 293 -webkit-transform: translate(" + coord.x + "px, 0px); 294 transform: translate(" + coord.x + "px, 0px); 295 } 296 } 297 @-webkit-keyframes parabola-ver-animation{ 298 0%{ 299 -webkit-transform: translate(0px, 0px); 300 transform: translate(0px, 0px); 301 } 302 10%{ 303 -webkit-transform: translate(0px, " + coord.os + "px); 304 transform: translate(0px, " + coord.os + "px); 305 } 306 100%{ 307 -webkit-transform: translate(0px," + coord.y + "px); 308 transform: translate(0px," + coord.y + "px); 309 } 310 } 311 @keyframes parabola-ver-animation{ 312 0%{ 313 -webkit-transform: translate(0px, 0px); 314 transform: translate(0px, 0px); 315 } 316 10%{ 317 -webkit-transform: translate(0px, " + coord.os + "px); 318 transform: translate(0px, " + coord.os + "px); 319 } 320 100%{ 321 -webkit-transform: translate(0px," + coord.y + "px); 322 transform: translate(0px," + coord.y + "px); 323 } 324 } 325 "; 326 cssAnimation.innerHTML = rules; 327 return cssAnimation; 328 }, 329 creatHtml: function(site, img ,callback) { 330 var imgHtml = img == '' ? '' : '<img src="' + img + '">'; 331 332 var html = '<div class="parabola-box-hor"> 333 <div class="parabola-box-ver"> 334 ' + imgHtml + ' 335 </div> 336 </div>'; 337 338 var parentBox = document.createElement('div'); 339 parentBox.innerHTML = html; 340 parentBox.setAttribute('class', 'parabola-animation'); 341 342 $(parentBox).on('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', '.parabola-box-ver', function() { 343 var _pfly = $(parentBox); 344 if (_pfly.length) _pfly.remove(); 345 callback(); 346 }); 347 var frag = document.createDocumentFragment(); 348 frag.appendChild(parentBox); 349 350 var verBox = frag.querySelector('.parabola-box-ver'), 351 horBpx = frag.querySelector('.parabola-box-hor'); 352 verBox.style.left = site.left + 'px'; 353 verBox.style.top = site.top + 'px'; 354 355 if (site.cubic) { 356 verBox.setAttribute("class", 'parabola-box-ver top'); 357 horBpx.setAttribute("class", 'parabola-box-hor top'); 358 } 359 return frag; 360 }, 361 calculatedValue: function(opt) { 362 var fly = { 363 begin: '', 364 end: '', 365 img: '', 366 callback: function() { 367 console.log('动画完成'); 368 } 369 }, 370 vData = { 371 site: { 372 left: 0, 373 top: 0, 374 cubic: false 375 }, 376 img: '', 377 coord: { 378 x: 0, 379 y: 0, 380 os: 0 381 }, 382 callback: function() {} 383 }, 384 _this = this; 385 386 if (typeof opt == 'object') { 387 fly = $.extend(true, fly, opt); 388 } 389 390 //如果没有这两个元素中的其中一个则终止 391 if (!fly.begin.length || !fly.end.length) return vData; 392 /** 393 * beginCrood 获取开始元素的位置 394 * endCrood 获取结束元素的位置 395 */ 396 var beginCrood = fly.begin[0].getBoundingClientRect(), 397 endCrood = fly.end[0].getBoundingClientRect(); 398 399 /*! 400 * 购物车动画出现的位置 401 * left: 开始元素的left+width/2 402 * top: 开始元素的top 403 * 购物车动画结束的位置 404 * x: 结束元素的left+width/2 再减去购物车动画出现的位置的left 405 * y: 结束元素的top+height/2 再减去购物车动画出现的位置的top 406 */ 407 /** 408 * 全部减去 18是因为购物车宽度和高度都是35px;一半难得算(-_-),就填18 409 */ 410 vData.site.left = beginCrood.left + parseInt(beginCrood.width / 2, 10) - 18; 411 vData.site.top = beginCrood.top - 18; 412 vData.coord.x = endCrood.left + parseInt(endCrood.width / 2, 10) - vData.site.left - 18; 413 vData.coord.y = endCrood.top + parseInt(endCrood.height / 2, 10) - vData.site.top - 18; 414 vData.coord.os = -50; 415 vData.img = fly.img; 416 vData.callback = fly.callback; 417 if (beginCrood.top > endCrood.top) vData.site.cubic = true; 418 419 return vData; 420 } 421 } 422 return new parabola(opt); 423 })(); 424 } 425 426 </script> 427 428 <script> 429 $('body').on('click', '.top', function() { 430 addCar({ 431 begin: $('.top'), 432 end: $('.bottom'), 433 img: './img/logo.jpg', 434 callback: function() { 435 console.log('动画完成'); 436 } 437 }) 438 }); 439 </script>