时间:2023-05-18 22:36:02 | 来源:网站运营
时间:2023-05-18 22:36:02 来源:网站运营
弹指间,网页灰飞烟灭——Google灭霸彩蛋实现:这是之前在公众号写的一篇文章,我觉得蛮有意思,这里再回顾下。
阅读本文大概需要 12 分钟。不知道大家有没有看这段时间最火的一部电影《复仇者联盟4:终局之战》,作为漫威迷的我还没看,为什么呢?因为太贵了,刚上映的那周,一张IMAX厅的票价已经达到了299的天价,作为搬砖民工是舍不得花这么高的钱来看一场电影的,太奢侈了,当然也可能我是个假漫威迷吧,哈哈哈哈逃~
<div class="box"> <div class="bomb">啪嗒!</div> <ul> <li class="item"> <h3>襟三江而带五湖,控蛮荆而引瓯越。</h3> </li> <li class="item"> <h3>潦水尽而寒潭清,烟光凝而暮山紫。</h3> </li> <li class="item"> <h3>落霞与孤鹜齐飞,秋水共长天一色。</h3> </li> <li class="item"> <img src="./1.jpg" /> </li> </ul></div>
样式就不贴了,后面会给出源码。<script src="./html2canvas.js"></script>
接着将元素转化为32个canvas。html2canvas(ele).then(dom => { const { width, height } = dom; // canvas宽高 let ctx = dom.getContext('2d'); // canvas绘图对象 // 返回一个ImageData对象,用来描述canvas区域隐含的像素数据,这个区域通过矩形表示,起始点为(sx, sy)、宽为sw、高为sh。 let originalFrame = ctx.getImageData(0, 0, width, height); // 创建一个32个新的、空白的、指定大小的 ImageData 对象。 所有的像素在新对象中都是透明的。 let frames = []; for (let i = 0; i < COUNT; i++) { frames[i] = ctx.createImageData(width, height); } // 将canvas所有的数据随机复制到32个frames上面 for (x = 0; x < width; ++x) { for (y = 0; y < height; ++y) { // frames 的下表索引值。 // 不是一般的(从0到COUNT的)随机值,而是递增的随机数,为了将像素点先集中在前几个frame,然后再往后集中,否则32个frames钟的像素太分散。 var frameIndex = Math.floor((COUNT * (Math.random() + (2 * x) / width)) / 3); // imageData.data:描述一个一维数组,包含以 RGBA 顺序的数据,数据使用 0 至 255(包含)的整数表示。 // 数组的个数为 width*height*4,所以除了宽乘高以外还要乘以4 var pixelIndex = 4 * (y * width + x); // 之所以要循环4次是因为上面乘了4,得到的 pixelIndex 在 width*height*4 范围内会有一些空缺,所以要补上这些空缺,保证所有的canvas像素全部复制到32个frames上面 for (offset = 0; offset < 4; offset++) { frames[frameIndex].data[pixelIndex + offset] = originalFrame.data[pixelIndex + offset]; } } }});
然后将这32个分布了不同像素点的 ImageData 对象转换成原始li元素大小的dom元素,用一个容器container来容纳,然后将容器覆盖到原始li元素的位置,现在就相当于每个li元素的位置是一个container元素,这个container元素内容是32个dom元素,这32个dom重叠起来的样子和原始li元素是一样的。// 创建一个div容纳frameslet container = document.createElement('div');container.classList.add('container');container.style.width = `${width}px`;container.style.height = `${height}px`;// 将所有包含RGBA数据的frames绘制到绘图中,生成32份和原始dom一样的元素,只是内容不同,最后将这些元素放入container中。let frames2doms = frames.map((frameData, i) => { let domCopy = dom.cloneNode(true); domCopy.getContext('2d').putImageData(frameData, 0, 0); // 将数据从已有的 ImageData 对象绘制到位图的方法。 domCopy.style.transitionDelay = `${(1.35 * i) / frames.length}s`; //过渡效果开始前的delay时间(可自行调整),使得frames先从下标小的开始运动。 container.appendChild(domCopy); return domCopy;});
现在我们看到的效果和原始的是一样的,但是所有的li元素被隐藏了起来,显示的是由许许多多零散的元素拼凑出来的假象。// 让所有的canvas动起来// 原始dom相对定位,container绝对定位ele.classList.add('disintegrated');ele.appendChild(container);ele.style.border = '0';container.offsetLeft; // 没有该句,则无法实现动画效果// 为32份不同内容的dom元素添加过渡效果(可自行调整)frames2doms.map(item => { let random = 2 * Math.PI * (Math.random() - 0.5); item.style.transform = ` rotate(${15 * (Math.random() - 0.5)}deg) translate(${60 * Math.cos(random)}px, ${30 * Math.sin(random)}px) rotate(${-15 * (Math.random() - 0.5)}deg) `; item.style.opacity = 0;});
三、实验效果关键词:实现