彈指間,網頁灰飛煙滅——Google滅霸彩蛋實現

不知道你們有沒有看這段時間最火的一部電影《復仇者聯盟4:終局之戰》,做爲漫威迷的我還沒看,爲何呢?由於太貴了,剛上映的那周,一張IMAX廳的票價已經達到了299的天價,做爲搬磚民工是捨不得花這麼高的錢來看一場電影的,太奢侈了,固然也可能我是個假漫威迷吧,哈哈哈哈逃~html

我剛看下如今的票價,IMAX廳是89元,已經接近正常,雖然仍是些許偏高,可是已經能夠接受了。對於看電影,我並非那麼崇尚看首映,或者非要第一時間看到,可是對於喜歡的電影我必定會找個最佳的位置觀看,如今票價合理,最佳觀影區充足,正是看電影的好時機。從這方面看,我可能只算是一個漫威愛好者,而毫不是一個狂熱者。前端

而今天要說的主題天然和漫威有關,是一個Google的小彩蛋。想必你們已經知道了,在Google中搜索「滅霸」,而後在右側點擊的「無限手套」,頁面的一些搜索項就會隨機性像沙子同樣的消失(後面統稱沙化效果),特別的炫酷。有不知道的能夠看下面的動圖:canvas

我以爲特別有意思,就參考了一些文章,實現了相似上面的沙化效果。數組

首先我製做了一個模板以下,點擊按鈕後,列表隨機沙化(手套的效果是不少圖片的合成,這裏就不處理了)。瀏覽器

模板代碼以下:服務器

<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>
複製代碼

樣式就不貼了,後面會給出源碼。 而後咱們一步步說明如何實現沙化效果。 首先,咱們將每個li元素的沙化封裝成一個函數 disintegrate ,這個函數參數就是要沙化的目標元素,這裏是li元素。微信

1、實現原理

簡單來講就是將頁面的元素先轉化爲canvas,而後提取出全部的像素點分別按照規律排布在32個canvas上面,,再將這些canvas轉換爲和原始元素大小同樣的dom元素堆疊在一塊兒,看起來就和原始元素同樣的,而後將原始元素隱藏。最後將這些堆疊在一塊兒的元素散開,就造成「沙化」的效果。app

2、實現步驟

首先引入 html2canvas 插件。 因爲須要將頁面的元素轉換成 canvas 圖像,因此要用到 html2canvas 插件(插件可自行到官網下載,官網地址:html2canvas.hertzen.com/)。dom

<script src="./html2canvas.js"></script>
複製代碼

接着將元素轉化爲32個canvas。 建立32個canvas(固然,個數越多,沙子就越細),把元素的每個像素複製到這32個canvas上面,這個每一個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容納frames
let 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;
});
複製代碼

3、實驗效果

點擊按鈕以後,每一個li元素位置的32個dom旋轉跳躍並閉上眼,哦不是逐漸消失。由於每一個dom上都只有一些小點並且在向不一樣的方向擴散,因此感受上就像沙化了。

4、注意事項

若是元素中有圖片的話,須要使用服務器的方式加載,不能使用本地瀏覽器直接打開,不然包含圖片的元素沒法沙化。

想要了解更多前端方面的內容能夠關注個人微信公衆號[前端隊長],咱們一同成長,一同領略技術與生活「落霞與孤鶩齊飛,秋水共長天一色」的美好。

關注公衆號,後臺回覆「滅霸」獲取源碼和素材。

參考連接:www.weibo.com/1727858283/…

相關文章
相關標籤/搜索