1. 程式人生 > >【Share Code | HTML & CSS & Javascript】動畫片段幻燈片

【Share Code | HTML & CSS & Javascript】動畫片段幻燈片

資源下載:

介紹

本文使用"Pieces"庫輕鬆實現動畫片段幻燈片效果。
image

今天我們想向您展示如何建立一個具有動畫片段幻燈片效果的圖片。 圖片被分成多個片段,這些片段將以不同的方式進行動畫製作,使用Pieces,可以輕鬆實現這些有趣的效果。

這將是最終結果:
image

最初的想法

這種效果的靈感來源Dribbble的Shift動畫:
Shift Animation (轉移動畫)

開始使用Pieces

有關Pieces庫的所有詳細文件都可以在其Github儲存庫中找到。 但無論如何,讓我們快速看到一些基本概念,以便能夠開始使用這個庫。

如果我們要繪製一個帶有動畫的圖片,這些是構成場景的基本元素:

image

Pieces Basic Elements (Pieces基本元素)

如您所見,我們想要繪製的影象將是我們的項item,它被分成幾個pieces,根據我們定義的選項,它們的大小和位置也可能不同。 要檢視所有可能的選項,我建議您檢視Github上的文件

在整個教程中,我們將解釋每段程式碼,以便您可以學習如何使用Pieces庫實現自己的動畫。 開始吧!

HTML 結構

在開始編寫Javascript程式碼之前,讓我們看看我們如何為slider定義HTML。 標記非常簡單,因為我們每個幻燈片都有相應的影象和文字,canvas元素用於動畫,而按鈕用於瀏覽slider。

<!-- Pieces Slider -->
<div class="pieces-slider"
>
<!-- 每一個slider都有對應的影象和文字 --> <div class="pieces-slider__slide"> <img class="pieces-slider__image" src="img/ricardo-gomez-angel-381749.jpg" alt=""> <div class="pieces-slider__text">Ricardo Gomez Angel</div> </div> <div class="pieces-slider__slide"
>
<img class="pieces-slider__image" src="img/josh-calabrese-527813.jpg" alt=""> <div class="pieces-slider__text">Josh Calabrese</div> </div> <div class="pieces-slider__slide"> <img class="pieces-slider__image" src="img/samuel-zeller-103111.jpg" alt=""> <div class="pieces-slider__text">Samuel Zeller</div> </div> <div class="pieces-slider__slide"> <img class="pieces-slider__image" src="img/sweet-ice-cream-photography-143023.jpg" alt=""> <div class="pieces-slider__text">Sweet Ice Cream</div> </div> <div class="pieces-slider__slide"> <img class="pieces-slider__image" src="img/sticker-mule-199237.jpg" alt=""> <div class="pieces-slider__text">Sticker Mule</div> </div> <!-- Canvas 繪製 pieces --> <canvas class="pieces-slider__canvas"></canvas> <!-- Slider 按鈕: prev 和 next --> <button class="pieces-slider__button pieces-slider__button--prev">prev</button> <button class="pieces-slider__button pieces-slider__button--next">next</button> </div>

設定slider的樣式

需要一些特殊的樣式來實現我們的效果。 我們需要隱藏影象和文字,因為我們將使用我們的庫重繪它們。 但是如果沒有可用的JavaScript,我們也希望它們回退到它們的初始標記。 最後,我們需要確保slider響應媒體查詢:

.pieces-slider {
    position: relative;
    text-align: center;
    padding: 8rem 0;
}

.js .pieces-slider {
    padding: 0;
}

/* Make all slides absolutes and hide them */
.js .pieces-slider__slide {
    position: absolute;
    right: 100%;
}

/* Define image dimensions and also hide them */
.pieces-slider__image {
    max-width: 600px;
    max-height: 400px;
}

.js .pieces-slider__image {
    visibility: hidden;
}

/* Hide the titles */
.js .pieces-slider__text {
    text-indent: -9999px;
}

/* Canvas with viewport width and height */
.js .pieces-slider__canvas {
    position: relative;
    width: 100vw;
    height: 100vh;
    transition: 0.2s opacity;
}

/* Class for when we resize */
.pieces-slider__canvas--hidden {
    opacity: 0;
    transition-duration: 0.3s;
}

/* Navigation buttons */
.pieces-slider__button {
    position: absolute;
    left: 0;
    top: 50%;
    width: 100px;
    height: 100px;
    margin: -25px 0 0 0;
    background-color: #5104ab;
    color: #fff;
    font-family: inherit;
    font-weight: bold;
    border: none;
    cursor: pointer;
    transition: 0.1s background-color;
}

.pieces-slider__button:hover {
    background: #5f3abf;
}

.pieces-slider__button--next {
    left: auto;
    right: 0;
}

/* Hide the buttons when no JS */
.no-js .pieces-slider__button {
    display: none;
}

/* Media queries with styles for smaller screens */
@media screen and (max-width: 720px) {
    .pieces-slider__image {
        max-width: 300px;
    }
}

@media screen and (max-width: 55em) {
    .pieces-slider__canvas {
        width: 100vw;
        height: 100vw;
    }
    .pieces-slider__button {
        width: 60px;
        height: 60px;
    }
}

如您所見,我們隱藏了我們為滑塊定義的HTML元素(按鈕除外),因為我們將在canvas元素中繪製所有內容。

使用Pieces為slider設定動畫

讓我們定義一些變數並從DOM獲取slider資訊:

// Get all images and texts, get the `canvas` element, and save slider length
var sliderCanvas = document.querySelector('.pieces-slider__canvas');
var imagesEl = [].slice.call(document.querySelectorAll('.pieces-slider__image'));
var textEl = [].slice.call(document.querySelectorAll('.pieces-slider__text'));
var slidesLength = imagesEl.length;

然後我們需要定義索引變數來處理我們在畫布上繪製的所有item:

// Define indexes related variables, as we will use indexes to reference items
var currentIndex = 0, currentImageIndex, currentTextIndex, currentNumberIndex;
var textIndexes = [];
var numberIndexes = [];

// Update current indexes for image, text and number
function updateIndexes() {
    currentImageIndex = currentIndex * 3;
    currentTextIndex = currentImageIndex + 1;
    currentNumberIndex = currentImageIndex + 2;
}
updateIndexes();

現在我們將開始為每種型別的專案(影象,文字,數字和按鈕)定義選項。 您可以在Pieces文件中找到完整的參考,這裡詳細解釋了用於繪製圖像的每個選項的作用:

// Options for images
var imageOptions = {
    angle: 45, // rotate item pieces 45deg
    extraSpacing: {extraX: 100, extraY: 200}, // this extra spacing is needed to cover all the item, because angle != 0
    piecesWidth: function() { return Pieces.random(50, 200); }, // every piece will have a random width between 50px and 200px
    ty: function() { return Pieces.random(-400, 400); } // every piece will be translated in the Y axis a random distance between -400px and 400px
};

同樣,我們將為其他項型別定義選項。 請參閱註釋以瞭解所使用的一些屬性:

/ Options for texts
var textOptions = {
    color: 'white',
    backgroundColor: '#0066CC',
    fontSize: function() { return windowWidth > 720 ? 50 : 30; },
    padding: '15 20 10 20',
    angle: -45,
    extraSpacing: {extraX: 0, extraY: 300},
    piecesWidth: function() { return Pieces.random(50, 200); },
    ty: function() { return Pieces.random(-200, 200); },
    translate: function() {
        if (windowWidth > 1120) return {translateX: 200, translateY: 200};
        if (windowWidth > 720) return {translateX: 0, translateY: 200};
        return {translateX: 0, translateY: 100};
    }
};

// Options for numbers
var numberOptions = {
    color: 'white',
    backgroundColor: '#0066CC',
    backgroundRadius: 300,
    fontSize: function() { return windowWidth > 720 ? 100 : 50; },
    padding: function() { return windowWidth > 720 ? '18 35 10 38' : '18 25 10 28'; },
    angle: 0,
    piecesSpacing: 2,
    extraSpacing: {extraX: 10, extraY: 10},
    piecesWidth: 35,
    ty: function() { return Pieces.random(-200, 200); },
    translate: function() {
        if (windowWidth > 1120) return {translateX: -340, translateY: -180};
        if (windowWidth > 720) return {translateX: -240, translateY: -180};
        return {translateX: -140, translateY: -100};
    }
};

現在我們為每種型別的專案提供了所有選項,讓它們放在一起將它傳遞給Pieces庫!

// Build the array of items to draw using Pieces
var items = [];
var imagesReady = 0;
for (var i = 0; i < slidesLength; i++) {
    // Wait for all images to load before initializing the slider and event listeners
    var slideImage = new Image();
    slideImage.onload = function() {
        if (++imagesReady == slidesLength) {
            initSlider();
            initEvents();
        }
    };
    // Push all elements for each slide with the corresponding options
    items.push({type: 'image', value: imagesEl[i], options: imageOptions});
    items.push({type: 'text', value: textEl[i].innerText, options: textOptions});
    items.push({type: 'text', value: i + 1, options: numberOptions});
    // Save indexes
    textIndexes.push(i * 3 + 1);
    numberIndexes.push(i * 3 + 2);
    // Set image src
    slideImage.src = imagesEl[i].src;
}

除了構建元素陣列之外,在前面的程式碼塊中,我們定義了一個簡單的機制,只有在載入了所有影象時才呼叫initSlider函式。 這非常重要,因為我們無法使用Pieces繪製不可用的影象。

到目前為止,我們還沒有畫任何東西,但我們現在已經準備好了。 讓我們看看我們如何初始化一個新的Pieces例項。

// Save the new Pieces instance
piecesSlider = new Pieces({
    canvas: sliderCanvas, // CSS selector to get the canvas
    items: items, // the Array of items we've built before
    x: 'centerAll', // center all items in the X axis
    y: 'centerAll', // center all items in the Y axis
    piecesSpacing: 1, // default spacing between pieces
    fontFamily: ["'Helvetica Neue', sans-serif"],
    animation: { // animation options to use in any operation
        duration: function() { return Pieces.random(1000, 2000); },
        easing: 'easeOutQuint'
    },
    debug: false // set `debug: true` to enable debug mode
});

現在,所有的items和pieces都可以新增動畫。 它們實際上已經建立的好了,但預設是隱藏的,所以,讓我們看看如何顯示第一張幻燈片並啟動我們想要的動畫:

// Animate all numbers to rotate clockwise indefinitely
piecesSlider.animateItems({
    items: numberIndexes,
    duration: 20000,
    angle: 360,
    loop: true
});

// Show current items: image, text and number
showItems();

因此,要顯示和隱藏當前專案,我們需要分別呼叫showItems和hideItems函式。 我們已經實現瞭如下:

// Show current items: image, text and number
function showItems() {
    // Show image pieces
    piecesSlider.showPieces({items: currentImageIndex, ignore: ['tx'], singly: true, update: (anim) => {
        // Stop the pieces animation at 60%, and run a new indefinitely animation of `ty` for each piece
        if (anim.progress > 60) {
            var piece = anim.animatables[0].target;
            var ty = piece.ty;
            anime.remove(piece);
            anime({
                targets: piece,
                ty: piece.h_ty < 300
                    ? [{value: ty + 10, duration: 1000}, {value: ty - 10, duration: 2000}, {value: ty, duration: 1000}]
                    : [{value: ty - 10, duration: 1000}, {value: ty + 10, duration: 2000}, {value: ty, duration: 1000}],
                duration: 2000,
                easing: 'linear',
                loop: true
            });
        }
    }});
    // Show pieces for text and number, using alternate `ty` values
    piecesSlider.showPieces({items: currentTextIndex});
    piecesSlider.showPieces({items: currentNumberIndex, ty: function(p, i) { return p.s_ty - [-3, 3][i % 2]; }});
}

// Hide current items: image, text and number
function hideItems() {
    piecesSlider.hidePieces({items: [currentImageIndex, currentTextIndex, currentNumberIndex]});
}

最後,為了瀏覽slides,我們已經定義了這些功能:

// Select the prev slide: hide current items, update indexes, and show the new current item
function prevItem() {
    hideItems();
    currentIndex = currentIndex > 0 ? currentIndex - 1 : slidesLength - 1;
    updateIndexes();
    showItems();
}

// Select the next slide: hide current items, update indexes, and show the new current item
function nextItem() {
    hideItems();
    currentIndex = currentIndex < slidesLength - 1 ? currentIndex + 1 : 0;
    updateIndexes();
    showItems();
}

因此,如果單擊導航按鈕或按下某些箭頭鍵(向左或向右),我們需要呼叫這些函式:

// Select prev or next slide using buttons
prevButtonEl.addEventListener('click', prevSlide);
nextButtonEl.addEventListener('click', nextSlide);

// Select prev or next slide using arrow keys
document.addEventListener('keydown', function (e) {
    if (e.keyCode == 37) { // left
        prevSlide();
    } else if (e.keyCode == 39)