[查看demo & 下载资源](https://zhaoshuquan.com/posts/15

介绍

本文使用"Pieces"库轻松实现动画片段幻灯片效果。

今天我们想向您展示如何创建一个具有动画片段幻灯片效果的图片。 图片被分成多个片段,这些片段将以不同的方式进行动画制作,使用Pieces,可以轻松实现这些有趣的效果。

这将是最终结果:

动画由anime.js提供支持。

最初的想法

这种效果的灵感来源Dribbble的Shift动画:

开始使用Pieces

有关Pieces库的所有详细文档都可以在其Github存储库中找到。 但无论如何,让我们快速看到一些基本概念,以便能够开始使用这个库。

如果我们要绘制一个带有动画的图片,这些是构成场景的基本元素:

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) { // right
nextSlide();
}
});

我们差不多完成

【Share Code | HTML & CSS & Javascript】动画片段幻灯片的更多相关文章

  1. 一些非常有用的html,css,javascript代码片段(持久更新)

    1.判断设备是否联网 if (navigator.onLine) { //some code }else{ //others code } 2.获取url的指定参数 function getStrin ...

  2. 惊人的CSS和JavaScript动画logos例子

    https://codepen.io/lindell/pen/mEVgJP Stack Overflow logo是我最喜欢的logo之一,因为它非常简单,但易于识别.并且这个片段动画点击预览Stac ...

  3. 梅须逊雪三分白,雪却输梅一段香——CSS动画与JavaScript动画

    CSS动画并不是绝对比JavaScript动画性能更优越,开源动画库Velocity.js等就展现了强劲的性能. 一.两者的主要区别 先开门见山的说说两者之间的区别. 1)CSS动画: 基于CSS的动 ...

  4. 利用 share code 插件同步代码片段

    利用 Settings Sync可以同步 VS code 配置,但它只能同步插件,利用  Settings Sync 再配合 share code 插件可以同步自定义代码片段,可以把 VS code ...

  5. Javascript动画效果(一)

    Javascript动画效果(一) 前面我们介绍了Javascript的回到顶部效果,今天呢,我们对Javascript动画做进一步的研究.在这篇博文中我们只介绍简单的匀速运动.简单的缓冲运动和简单的 ...

  6. Win10系列:JavaScript 动画1

    在应用程序中使用动画会使应用显得更加生动,进而给用户带来良好的视觉效果.例如,当用户将某个项添加到列表时,新项不会立即出现在列表中,而是采用动画形式到达相应位置,并且列表中的其他项也采用动画形式移动到 ...

  7. CSS变形动画

    CSS变形动画 前言 在开始介绍CSS变形动画之前,可以先了解一下学习了它之后能做什么,有什么用,这样你看这篇文章可能会有一些动力. 学习了CSS变形动画后,你可以为你的页面做出很多炫酷的效果,如一个 ...

  8. Javascript动画效果(三)

    Javascript动画效果(三) 前面我们已经介绍了速度动画.透明度动画.多物体运动和任意值变化,并且我们在Javascript动画效果(二)中介绍到我们封装了一个简单的插件雏形,接下来我们对前面的 ...

  9. Javascript动画效果(二)

    Javascript动画效果(二) 在前面的博客中讲了简单的Javascript动画效果,这篇文章主要介绍我在改变之前代码时发现的一些问题及解决方法. 在前面的多物体宽度变化的例子中,我们给其增加代码 ...

随机推荐

  1. 动态加载js不执行解决办法

    这个问题的产生原因是:我们项目有一个主index文件,在主index文件中需要根据参数来判断是加载pc.html的内容还是加载mobile.html的内容,一开始是使用jquery来做的,没有问题,后 ...

  2. flask的session基础认识

    from flask import Flask,session from datetime import timedelta import os app = Flask(__name__) app.c ...

  3. [转帖]英特尔首款采用10nm技术的混合CPU“Lakefield”即将发布

    英特尔首款采用10nm技术的混合CPU“Lakefield”即将发布 intel 也出soc了 里面的东西 跟 安卓和 apple的a系列很像. https://baijiahao.baidu.com ...

  4. 石子合并2——区间DP【洛谷P1880题解】

    [区间dp让人头痛……还是要多写些题目练手,抽空写篇博客总结一下] 这题区间dp入门题,理解区间dp或者练手都很妙 ——题目链接—— (或者直接看下面) 题面 在一个圆形操场的四周摆放N堆石子,现要将 ...

  5. Web项目测试流程总结

    个人知识脑图总结 - 未完全(工作项目脑图总结存于网盘中)

  6. 深入理解计算机系统 第十二章 并发编程 part1 第二遍

    三种构造并发程序的方法及其优缺点 1.进程 用这种方法,每个逻辑控制流都是一个进程,由内核来调度和维护.因为进程有独立的虚拟地址空间,想要和其他流通信,控制流必须使用某种显式的进程间通信机制. 优点: ...

  7. JavaScript设计模式(装饰者模式)

    一.模拟传统面向对象语言的装饰者模式: 假设我们在编写一个飞机大战的游戏,随着经验值的增加,我们操作的飞机对象可以升级成更厉害的飞机,一开始这些飞机只能发射普通的子弹,升到第二级时可以发射导弹,升到第 ...

  8. CentOS7 yum安装Mariadb

    1.安装Mariadb #yum -y install mariadb mariadb-server 1.1当执行程序末端显示Complete则完成安装 2.安装完成后启动服务 # systemctl ...

  9. 【原创】大数据基础之ETL vs ELT or DataWarehouse vs DataLake

    ETL ETL is an abbreviation of Extract, Transform and Load. In this process, an ETL tool extracts the ...

  10. 学习笔记--三分法&秦九韶算法

    前言 其实也没什么好说的吧,三分法就是用来求一个单调函数的最值和满足最大值的\(x\),秦九韶算法就是在\(O(N)\)时间内求一个多项式值 怎么用 三分法使用--看这篇:https://www.cn ...