├── README.md ├── boomExample.gif ├── boomExample2.gif └── src ├── Boom.js ├── cd_glaive.cur ├── cd_glowsword.cur ├── css └── Boom.css ├── demo.html ├── images.jpg ├── images ├── images.jpg └── images2.jpg ├── images2.jpg └── js └── Boom.js /README.md: -------------------------------------------------------------------------------- 1 | # boomJS 2 | 3 | 一个有趣的动画效果,用 `JavaScript` 配合 `CSS3` 实现让图片爆炸的动画。 4 | 5 | [Demo演示戳我](https://chokcoco.github.io/demo/boom/demo.html) 6 | 7 | ### Example 8 | 9 |  10 | 11 |  12 | 13 | ## Usage 14 | 15 | ```HTML 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 32 | ``` 33 | 34 | ## API 35 | ```javascript 36 | boom($('img'),{ 37 | // 缩放值 38 | 'scaleLevel' : 3, 39 | // 模糊值 40 | 'blurLevel': 9, 41 | // 弹射距离 42 | 'boomLevel': 4, 43 | // 爆炸时长 44 | 'boomTime':800, 45 | // 是否打开日志 46 | 'isOpenLog':true 47 | }); 48 | ``` 49 | 温馨提示,不建议将 scaleLevel 的值设太高 :) 。 50 | 51 | -------------------------------------------------------------------------------- /boomExample.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chokcoco/boomJS/74c9ea9c2f39300696ef6f317225d434907f65c2/boomExample.gif -------------------------------------------------------------------------------- /boomExample2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chokcoco/boomJS/74c9ea9c2f39300696ef6f317225d434907f65c2/boomExample2.gif -------------------------------------------------------------------------------- /src/Boom.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Coco 3 | * QQ:308695699 4 | * @name boomJS 1.0.0 5 | * @description 一个有趣的效果,用 JavaScript 实现让图片爆炸的动画(非Canvas) 6 | * -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 7 | * 1、本组件用于是学习 jQuery 队列时做的一个小 demo,使用 JavaScript 配合 CSS3 实现一个简单的动画效果 8 | * 9 | * 2、依赖 jQuery,且需要引入 Boom.css ; 10 | 11 | * 3、初始化方法, 12 | * 1)提供 var bom = new boom() 构造函数,构建 boom 实例,调用 bom.boom(),传入 img 的 jQuery 对象,例如bom.boom($('img')) 13 | * 2)直接 boom() 进行调用,传入 img 的 jQuery 对象,例如 boom($('img')) 14 | * 15 | * 4、目前只支持未经过缩放的图片 16 | * 17 | */ 18 | (function(window, undefined) { 19 | var 20 | // 是否插入了 jQuery 21 | isInsetJq = false, 22 | // css参数预设 23 | cssOption = { 24 | position: 'absolute', 25 | width: 0, 26 | height: 0, 27 | left: 0, 28 | top: 0 29 | }, 30 | // 存储图片地址 31 | imgUrl = "", 32 | // 暴露的最终变量 33 | boom = function(elems) { 34 | return new boom.prototype.init(elems); 35 | }, 36 | // 偏移距离 37 | arrRandomOffset = [1, -4, 8, -12, 16, -20, 24, -28, 32], 38 | // 图片集 39 | imgArr = [], 40 | // 传入的图片个数 41 | imgLength = 0; 42 | 43 | // 加载js 44 | function loadScript(url, callback) { 45 | if (isInsetJq) { 46 | return; 47 | } 48 | 49 | var ref = window.document.getElementsByTagName("script")[0], 50 | script = window.document.createElement("script"); 51 | 52 | script.src = url; 53 | script.type = 'text/javascript'; 54 | script.async = false; 55 | ref.parentNode.insertBefore(script, ref); 56 | 57 | if (callback && typeof(callback) === "function") { 58 | script.onload = callback; 59 | } 60 | 61 | isInsetJq = true; 62 | } 63 | 64 | // 计算坐标并添加新的层覆盖在原图上 65 | // 返回一个 jQuery 对象(dom 节点,是一个和图片高宽绝对定位坐标一致的 div) 66 | function calcPosition(elem) { 67 | imgUrl = elem.attr('src') || ""; 68 | 69 | // 转化为 JS 对象 70 | var obj = elem[0]; 71 | 72 | // getBoundingClientRect 方法返回元素的大小及其相对于视口的位置 73 | // 这是个 JS 对象方法,注意下文和 jQuery 对象的相互转换 74 | var posi = obj.getBoundingClientRect(), 75 | // 图片的宽高和定位 76 | elemCss = { 77 | width: obj.width, 78 | height: obj.height, 79 | top: posi.top, 80 | left: posi.left, 81 | }, 82 | // 生成新的 div 的 css 样式 83 | realCss = $.extend(cssOption, elemCss); 84 | 85 | var newDiv = $(document.createElement('div')); 86 | 87 | newDiv.css(realCss); 88 | 89 | $('body').append(newDiv); 90 | 91 | return newDiv; 92 | } 93 | 94 | /** 95 | * 在原图上生成小的 div 块 96 | * @param elem 原图的 jQuery 对象 97 | */ 98 | function insertSmallDiv(elem) { 99 | var obj = elem, 100 | width = elem.width(), 101 | height = elem.height(), 102 | miniNum = 10, 103 | widthNum = 0, 104 | heightNum = 0, 105 | // div 小块的宽度 106 | newElemWidth = 0, 107 | i = 0, 108 | j = 0, 109 | elemArr = []; 110 | 111 | //console.log(width+','+height); 112 | 113 | if (width <= 10 && height <= 10) { 114 | return; 115 | } 116 | 117 | var basePoint = width > height ? height : width; 118 | 119 | //console.log('base point is :'+basePoint); 120 | 121 | if (basePoint == width) { 122 | newElemWidth = Math.floor(width / miniNum); 123 | heightNum = Math.floor(height / newElemWidth); 124 | widthNum = miniNum; 125 | } else { 126 | newElemWidth = Math.floor(height / miniNum); 127 | heightNum = Math.floor(width / newElemWidth); 128 | widthNum = miniNum; 129 | } 130 | 131 | //console.log('widthNum:'+widthNum+',height:'+heightNum+',width:'+newElemWidth); 132 | 133 | var newElemCss = { 134 | position: 'absolute', 135 | width: newElemWidth, 136 | height: newElemWidth, 137 | 'border-radius': '100%', 138 | top: 0, 139 | left: 0 140 | } 141 | 142 | // 比较宽高大小,确定插入的行数 143 | if (height > width) { 144 | // 交换 width ,height 的值 145 | widthNum = widthNum * heightNum; 146 | heightNum = widthNum / heightNum; 147 | widthNum = widthNum / heightNum; 148 | } 149 | 150 | //console.log('widthNum:'+widthNum+',heightNum:'+heightNum+',newElemWidth:'+newElemWidth); 151 | 152 | for (; i < widthNum; i++) { 153 | for (; j < heightNum; j++) { 154 | var randomSize = Math.random() * 3, 155 | newElem = document.createElement('div'), 156 | cssTop = i * newElemWidth, 157 | cssLeft = j * newElemWidth, 158 | posiElemCss = { 159 | 'background-image': 'url(' + imgUrl + ')', 160 | 'background-repeat': 'no-repeat', 161 | 'background-position': '-' + cssLeft + 'px ' + '-' + cssTop + 'px', 162 | position: 'absolute', 163 | width: newElemWidth, 164 | height: newElemWidth, 165 | 'border-radius': '100%', 166 | top: 0, 167 | left: 0, 168 | top: cssTop, 169 | left: cssLeft, 170 | transform: 'scale(' + randomSize + ')' 171 | }; 172 | // console.log('cssTop is:'+cssTop+',cssLeft is:'+cssLeft+',posiElemCss:'+posiElemCss); 173 | // console.log(newElemCss); 174 | // var curElemCss = $.extend(newELemCss,posiElemCss); 175 | $(newElem).css(posiElemCss); 176 | elemArr.push(newElem); 177 | } 178 | j = 0; 179 | } 180 | //console.log(elemArr); 181 | elem.append(elemArr); 182 | } 183 | 184 | /** 185 | * 计算 boom 动画轨迹终止点 186 | * @param center 图片中心坐标 187 | * @param div 将要运动的图片坐标 188 | * @return {x,y} 返回点 div 的动画轨迹终止点 189 | */ 190 | function ramdomPosition(center, div) { 191 | var 192 | // 直线斜率 193 | slope = 0, 194 | // 爆炸范围 195 | randomBoomDis = Math.random() * 5, 196 | // 距离 197 | distance = randomBoomDis * (center.x > center.y ? center.x : center.y), 198 | // 结果 199 | result = { 200 | x: 0, 201 | y: 0 202 | }, 203 | // div 在中心点的上方还是下方 204 | isTop = center.y - div.y > 0 ? 1 : 0; 205 | 206 | if (center.x != div.x && center.y != div.y) { 207 | slope = (center.y - div.y) / (center.x - div.x); 208 | 209 | // y = kx + b 210 | var b = center.y - (slope * center.x); 211 | 212 | //console.log('斜率slope is:'+slope+',b is:'+b+',distance is:'+distance); 213 | 214 | // 轨迹终止的Y点 215 | // (2*div.y - center.y) : (distance + center.y) 216 | result.y = (isTop == true ? (2 * div.y - center.y) : (2 * div.y - center.y)) + ((Math.random() > 0.5 ? Math.random() * 4 : -Math.random() * 4)), 217 | // 轨迹终止的X点 218 | result.x = ((result.y - b) / slope) + ((Math.random() > 0.5 ? Math.random() * 4 : -Math.random() * 4)); 219 | 220 | return result; 221 | } else if (center.x == div.x) { 222 | if (center.y > div.y) { 223 | return { 224 | x: center.x, 225 | y: center.y - distance 226 | } 227 | } else { 228 | return { 229 | x: center.x, 230 | y: center.y + distance 231 | } 232 | } 233 | } else if (center.y == div.y) { 234 | if (center.x > div.x) { 235 | return { 236 | x: center.x - distance, 237 | y: center.y 238 | } 239 | } else { 240 | return { 241 | x: center.x + distance, 242 | y: center.y 243 | } 244 | } 245 | } else { 246 | return; 247 | } 248 | } 249 | 250 | boom.prototype = { 251 | init: function(elems) { 252 | var argLength = arguments.length; 253 | 254 | if (arguments[0] !== undefined) { 255 | this.boom(elems); 256 | } 257 | 258 | return this; 259 | }, 260 | boom: function(elems) { 261 | var elemLength = elems.length; 262 | 263 | if (!elemLength) { 264 | return; 265 | } else { 266 | elem = elems.eq(imgLength++).show(); 267 | } 268 | 269 | if (imgLength == elemLength) { 270 | imgLength = 0; 271 | } 272 | 273 | var randomNum = Math.random() * 2, 274 | certerPonit = { 275 | x: Math.floor(elem.width() / 2) + randomNum, 276 | y: Math.floor(elem.height() / 2) - randomNum 277 | } 278 | 279 | var newWrap = calcPosition(elem); 280 | // insertSmallDiv(newWrap); 281 | // elem.hide(); 282 | elem 283 | .delay(300, 'shake') 284 | .queue('shake', function(next) { 285 | // 300s 后隐藏原图 286 | $(this).animate({ 287 | opacity: 0 288 | }, { 289 | duration: 1 290 | }) 291 | next(); 292 | }) 293 | // 摇晃效果 294 | .dequeue('shake') 295 | .addClass('shake') 296 | .queue('shake', function() { 297 | insertSmallDiv(newWrap); 298 | 299 | var divs = newWrap.find('div'), 300 | length = divs.length, 301 | i = 0; 302 | 303 | for (; i < length; i++) { 304 | var div = divs.eq(i), 305 | divPoint = { 306 | x: parseInt(div.css('left')), 307 | y: parseInt(div.css('top')) 308 | } 309 | 310 | // 一些随机数添加 311 | var resultPoint = ramdomPosition(certerPonit, divPoint); 312 | //console.log(resultPoint); 313 | var randomOffset = arrRandomOffset[i % 9]; 314 | 315 | divs.eq(i).animate({ 316 | left: resultPoint.x + (Math.random() > 0.5 ? randomOffset : -randomOffset), 317 | top: resultPoint.y + (Math.random() > 0.5 ? randomOffset : -randomOffset), 318 | opacity: 0 319 | }, 800); 320 | } 321 | }); 322 | } 323 | } 324 | 325 | boom.prototype.init.prototype = boom.prototype; 326 | 327 | // 暴露变量 328 | window.boom = boom; 329 | 330 | })(window) 331 | -------------------------------------------------------------------------------- /src/cd_glaive.cur: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chokcoco/boomJS/74c9ea9c2f39300696ef6f317225d434907f65c2/src/cd_glaive.cur -------------------------------------------------------------------------------- /src/cd_glowsword.cur: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chokcoco/boomJS/74c9ea9c2f39300696ef6f317225d434907f65c2/src/cd_glowsword.cur -------------------------------------------------------------------------------- /src/css/Boom.css: -------------------------------------------------------------------------------- 1 | .shake{animation:shake 0.2s ease-in;-webkit-animation:shakeAm 0.2s ease-in} 2 | @keyframes shakeAm{ 3 | 0%{transform:rotateZ(0deg) translate(0,0)} 4 | 12.5%{transform:rotateZ(5deg) translate(6px,6px)} 5 | 25%{transform:rotateZ(0deg) translate(-4px,5px)} 6 | 37.5%{transform:rotateZ(-5deg) translate(-6px,-6px)} 7 | 50%{transform:rotateZ(0deg) translate(0,0)} 8 | 62.5%{transform:rotateZ(3deg) translate(3px,4px)} 9 | 75%{transform:rotateZ(0deg) translate(-3px,-2px)} 10 | 87.5%{transform:rotateZ(3deg) translate(3px,-2px)} 11 | 100%{transform:rotateZ(1deg) translate(-1px,1px)} 12 | } 13 | @-webkit-keyframes shakeAm{ 14 | 0%{transform:rotateZ(0deg) translate(0,0)} 15 | 12.5%{transform:rotateZ(5deg) translate(6px,6px)} 16 | 25%{transform:rotateZ(0deg) translate(-4px,5px)} 17 | 37.5%{transform:rotateZ(-5deg) translate(-6px,-6px)} 18 | 50%{transform:rotateZ(0deg) translate(0,0)} 19 | 62.5%{transform:rotateZ(3deg) translate(3px,4px)} 20 | 75%{transform:rotateZ(0deg) translate(-3px,-2px)} 21 | 87.5%{transform:rotateZ(3deg) translate(3px,-2px)} 22 | 100%{transform:rotateZ(1deg) translate(-1px,1px)} 23 | } 24 | @-moz-keyframes shakeAm{ 25 | 0%{transform:rotateZ(0deg) translate(0,0)} 26 | 12.5%{transform:rotateZ(5deg) translate(6px,6px)} 27 | 25%{transform:rotateZ(0deg) translate(-4px,5px)} 28 | 37.5%{transform:rotateZ(-5deg) translate(-6px,-6px)} 29 | 50%{transform:rotateZ(0deg) translate(0,0)} 30 | 62.5%{transform:rotateZ(3deg) translate(3px,4px)} 31 | 75%{transform:rotateZ(0deg) translate(-3px,-2px)} 32 | 87.5%{transform:rotateZ(3deg) translate(3px,-2px)} 33 | 100%{transform:rotateZ(1deg) translate(-1px,1px)} 34 | } 35 | -------------------------------------------------------------------------------- /src/demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 |