【Animejs】——Anime.js照片墙案例实现

【Animejs教程】一个绝赞易用的动画库 Animejs,一个绝好的threejs动画辅助库 前端动画库 animejs 使用教程 阅读详情

目录

一、实现的效果:

二、实现js的具体步骤

1、需要实现的逻辑梳理

2、切换风格的逻辑

三、完整代码:


用js编写使用animejs实现图片复杂的切换效果

一、实现的效果:

点击——> <——箭头,实现不同动画效果的炫酷切换 。

代码可以通过我下面分享的码云链接进行下载,或者结尾我会附上完整的代码:

animejs_1照片墙: 使用animejs实现照片墙的炫酷切换效果

我们主要来实现js部分的编写,所以建议大家去我的码云把源码下载下来,方便学习。 

二、实现js的具体步骤

创建如下的目录:

目录组成部分: 

 现在的状态是,画面在第一页上,点击两个箭头页面是不动的:

我们可以看到在index.html文件中,这7个风格都在里面,每一个风格我们用类名slide--layout-n中的数字来做区分:

如slide--layout-4代表第4种风格。

 这些风格都在页面中显示,为什么我们看不到?是因为透明度改成0。

我们需要做的是给按钮添加点击事件,使之能够切换风格: 

1、需要实现的逻辑梳理

点击箭头,会有两个效果:一个显示的图片出去,将要显示的图片进来的效果。

每次切换,标题也是不同的动画效果

总结我们需要完成的业务逻辑就是:

1、 我们切换风格的逻辑是通过改变每个风格的透明度来实现。

2、实现两个动画风格:图片的和标题的。——图片又分为进入和出去两个动画风格;标题每个风格都一样,我们写一个就可以了。

2、切换风格的逻辑

展示页面的逻辑:通过添加'slide--current'类名来实现透明度变为1,展示在页面上。

1、所有代码都是自执行函数,先实现两个方法,方便之后使用。

; (function (window) {
    // 严格模式下
	'use strict';
	// extend:把某一个对象的属性复制给另一个对象,把b的属性给a
	function extend(a, b) {
		for (var key in b) {
			if (b.hasOwnProperty(key)) {
				a[key] = b[key];
			}
		}
		return a;
	}
    // 防抖:我们不希望当快速点击的时候我们就一直在执行。想要间隔一定的时间在去触发 
	function debounce(func, wait) {
		var timeout;
		return function () {
			var context = this, args = arguments;
			var later = function () {
				timeout = null;
				func.apply(context, args);
			};
			clearTimeout(timeout);
			timeout = setTimeout(later, wait);
		};
	};
})(window)

2、实现风格切换的方法: 

function MLSlideshow(el, options) {
		// 1. 元素属性
        // 拿到元素,就把元素挂载到对象下
		this.el = el;
		// 2. 相关参数
		this.options = extend({}, this.options);
		extend(this.options, options);
		// 3. 所有照片的风格
        // 最外层盒子取到所有风格的类名
		this.slides = [].slice.call(this.el.querySelectorAll('.slide'));

		// 判断:如果当前照片风格少于2,不创建实例————也就是只有1种风格
		this.slidesTotal = this.slides.length;
		if (this.slidesTotal <= 1) {
			return;
		}
		// 4. 当前展示的风格的下标
		this.current = this.options.startIdx || 0;
		// 5. 当前窗口大小————因为图片的宽高是由窗口大小决定的
		this.dimentions = {
			width: this.el.offsetWidth,
			height: this.el.offsetHeight
		}
		// 6. 照片风格初始化
        // 需要一个_init方法————下面会写
		this._init();
	}

解释: 

this.slides = [].slice.call(this.el.querySelectorAll('.slide'));

如下图index.html中知道每个风格的类名都叫 slide ,this.el.querySelectorAll('.slide')返回的是一个伪数组数据,所以我们需要转化为正常的数组来方便之后处理,通过slice


3、风格初始化——_init

// 照片墙初始化
	MLSlideshow.prototype._init = function () {
		var self = this, // self保存一下当前的this
			// 1. 当图片加载完成,展示当前第一个风格————由current决定是第几个风格
			// onPreload:图片加载完成要做的事情
			onPreload = function () {
				// 给当前的图片添加一个类名
				self.el.classList.add('slideshow--loaded');
				// 让第一个风格展示
				self.slides[self.current].classList.add('slide--current');
			};
		// 在图片加载完成的时候调用
		this._preload(onPreload);
		// 2. 添加事件:
                // 2.1 窗口大小事件
                // 2.2 键盘触发切换风格事件
		// _initEvents独立出一个方法
		this._initEvents();

	}

解释:

 当图片加载完成之后,才会展示当前第一个风格,那么我们会用到一个插件:

这个插件里面通提供了一个方法imagesLoaded,来判断我们的图片是否加载完成。

// 判断图片是否加载完成
	MLSlideshow.prototype._preload = function (callback) {
		// imagesLoaded直接调用,因为我们已经引入了这个包
		imagesLoaded(this.el, { background: true }, function () {
			// 如果传入的回调是一个函数,我们就去调用它
			if (typeof callback === 'function') {
				callback();
			}
		});
	};

4、添加事件——_initEvents:

MLSlideshow.prototype._initEvents = function () {
		var self = this;
		// 2.1 窗口大小事件
		// 用到防抖debounce
		this.debounceResize = debounce(function (ev) {
			self.dimentions = {
				width: self.el.offsetWidth,
				height: self.el.offsetHeight
			};
		}, 10)
		// 添加事件,当窗口的大小发送改变: 
		window.addEventListener('resize', this.debounceResize);
		// 2.2 键盘触发切换风格事件
		// 按下左右键的键盘按键,触发切换的按钮
		this.keyboardFn = function (ev) {
			var keyCode = ev.keyCode || ev.which;
			switch (keyCode) {
				case 37:
					// _navigate('prev'):往前切换————一会完成前后切换的函数实现
					self._navigate('prev');
					break;
				case 39:
					// _navigate('next'):往后切换
					self._navigate('next');
					break;
			}
		};
		this.el.addEventListener('keydown', this.keyboardFn);
	}

5、前后切换——_navigate

// _navigate:参数接收prev和next
	MLSlideshow.prototype._navigate = function (direction) {
		// isAnimating:判断当前动画是否在运动
		if (this.isAnimating) {
			return false;
		}
		this.isAnimating = true;
		// 1. 获取当前展示风格的信息: 当前元素,唯一标识,相关标题
		var self = this,
			// 知道当前展示的下标是什么,当点击前后切换的时候,改变下标的值来完成
			currentSlide = this.slides[this.current],
			// 获取当前风格标识
			currentLayout = currentSlide.getAttribute('data-layout') || 'layout1',
			// 获取当前展示风格的标题
			currentTitle = currentSlide.querySelector('.slide__title');

		// 2. 获取下一个要展示风格的信息: 当前元素,唯一标识,相关标题
		if (direction === 'next') {
			this.current = this.current < this.slidesTotal - 1 ? this.current + 1 : 0;
		}
		else {
			this.current = this.current > 0 ? this.current - 1 : this.slidesTotal - 1;
		}
		// 获取元素信息
		var nextSlide = this.slides[this.current],
			nextLayout = nextSlide.getAttribute('data-layout'),
			nextTitle = nextSlide.querySelector('.slide__title');
        // 3. 针对要出去的元素的动画
		// currentSlide.querySelectorAll('.slide-imgwrap .slide__img-inner'):动画中要出去的所有的图片
		// currentSlide:当前要出去的元素
		var outItems = [].slice.call(currentSlide.querySelectorAll('.slide-imgwrap .slide__img-inner')),
			// 获取相关配置参数
			outconfig = this.options.layoutConfig[currentLayout] !== undefined ? this.options.layoutConfig[currentLayout].out : this.options.layoutConfig['layout1'].out,
			animeOutProps = {
				targets: outItems,
				duration: outconfig.duration,
				easing: outconfig.easing,
				// 延迟是一个方法
				delay: function (el, index) {
					return direction === 'next' ? index * outconfig.itemsDelay : (outItems.length - 1 - index) * outconfig.itemsDelay;
				},
				// 走的这个元素之前是添加了一个类名,现在走了要把类名拿掉
				complete: function () {
					currentSlide.classList.remove('slide--current');
				}
			};
		this._setAnimationProperties(animeOutProps, outconfig, direction)
		// 参数传入,直接进行动画
		anime(animeOutProps);
		// 标题
		this._anmateTitle(currentTitle, 'out');
		// 创建定时器:当前风格出去了,再让下一个风格进来
		clearTimeout(this.navtime);
		// animateIn:让动画进来  
		this.navtime = setTimeout(animateIn, this.options.layoutConfig[nextLayout] !== undefined && this.options.layoutConfig[nextLayout].in.delay !== undefined ? this.options.layoutConfig[nextLayout].in.delay : 150);
	}

针对要显示的风格创建方法:

// _navigate:参数接收prev和next
	MLSlideshow.prototype._navigate = function (direction) {
		// isAnimating:判断当前动画是否在运动
		if (this.isAnimating) {
			return false;
		}
		this.isAnimating = true;
		// 1. 获取当前展示风格的信息: 当前元素,唯一标识,相关标题
		var self = this,
			// 知道当前展示的下标是什么也就是要出去的元素,当点击前后切换的时候,改变下标的值来完成
			currentSlide = this.slides[this.current],
			// 获取当前风格标识
			currentLayout = currentSlide.getAttribute('data-layout') || 'layout1',
			// 获取当前展示风格的标题
			currentTitle = currentSlide.querySelector('.slide__title');

		// 2. 获取下一个要展示风格的信息: 当前元素,唯一标识,相关标题
		if (direction === 'next') {
			this.current = this.current < this.slidesTotal - 1 ? this.current + 1 : 0;
		}
		else {
			this.current = this.current > 0 ? this.current - 1 : this.slidesTotal - 1;
		}
		// 获取元素信息
		var nextSlide = this.slides[this.current],
			nextLayout = nextSlide.getAttribute('data-layout'),
			nextTitle = nextSlide.querySelector('.slide__title');
		// 4. 针对要显示的风格创建方法
		var animateIn = function () {

			// 开启动画之前把其他动画停掉
			clearTimeout(self.navtime);

			// 获取计算的要进入的风格的照片元素
			var inItems = [].slice.call(nextSlide.querySelectorAll('.slide-imgwrap .slide__img-inner')),
				// 设置计算的下一个的下标元素动画,如果不存在就设置第一个元素动画,标识区分
				// 获取即将进入的风格的动画参数
				inconfig = self.options.layoutConfig[nextLayout] !== undefined ? self.options.layoutConfig[nextLayout].in : self.options.layoutConfig['layout1'].in,
				// 进入时,初始化设置赋值给inresetconfig
				inresetconfig = inconfig.resetProps,
				// 设置动画参数
				animeInProps = {
					targets: inItems,
					duration: inconfig.duration,
					easing: inconfig.easing,
					delay: function (el, index) {
						return direction === 'next' ? index * inconfig.itemsDelay : (inItems.length - 1 - index) * inconfig.itemsDelay;
					},
					// 动画完成设置动画运动标识是false
					complete: function () {
						self.isAnimating = false;
					}
				};

			// Configure the animation in properties.
			// 将动画参数,当前动画元素相关信息,前后传入设置动画属性的方法中
			self._setAnimationProperties(animeInProps, inconfig, direction);
			// Reset before animating in:
			// 在动画之前重置即将进入的风格的图片
			// 需要重置的原因:因为图片的宽高是相对窗口的 ,但是图片的宽高又是根据浏览器窗口的,所以每一次我们都要重置一下图片的宽高,避免窗口发生改变之后,盒子小了图片还很大这种不好的效果
			inItems.forEach(function (item, pos) {
				var transformStr = '';
				// 将属性中的translateX、translateY、rotateZ、scale、opacity进行重置
				if (inresetconfig.translateX !== undefined) {
					var tx = typeof inresetconfig.translateX === 'object' ?
						function () {
							return typeof inresetconfig.translateX[direction] === 'function' ?
								self._getValuePercentage(inresetconfig.translateX[direction](item, pos), 'width') :
								self._getValuePercentage(inresetconfig.translateX[direction], 'width');
						} : self._getValuePercentage(inresetconfig.translateX, 'width');

					transformStr += ' translateX(' + (typeof tx === 'function' ? tx() : tx) + 'px)';
				}
				if (inresetconfig.translateY !== undefined) {
					var ty = typeof inresetconfig.translateY === 'object' ? function () {
						return typeof inresetconfig.translateY[direction] === 'function' ? self._getValuePercentage(inresetconfig.translateY[direction](item, pos), 'height') : self._getValuePercentage(inresetconfig.translateY[direction], 'height');
					} : self._getValuePercentage(inresetconfig.translateY, 'height');
					transformStr += ' translateY(' + (typeof ty === 'function' ? ty() : ty) + 'px)';
				}
				if (inresetconfig.rotateZ !== undefined) {
					var rot = typeof inresetconfig.rotateZ === 'object' ? function () {
						return typeof inresetconfig.rotateZ[direction] === 'function' ? inresetconfig.rotateZ[direction](item, pos) : inresetconfig.rotateZ[direction];
					} : inresetconfig.rotateZ;

					transformStr += ' rotateZ(' + (typeof rot === 'function' ? rot() : rot) + 'deg)';
				}
				if (inresetconfig.scale !== undefined) {
					var s = typeof inresetconfig.scale === 'object' ? function () {
						return typeof inresetconfig.scale[direction] === 'function' ? inresetconfig.scale[direction](item, pos) : inresetconfig.scale[direction];
					} : inresetconfig.scale;

					transformStr += ' scale(' + (typeof s === 'function' ? s() : s) + ')';
				}
				if (transformStr !== '') {
					item.style.transform = item.style.WebkitTransform = transformStr;
				}
				if (inresetconfig.opacity !== undefined) {
					item.style.opacity = inresetconfig.opacity;
				}
			});
			// 设置即将进入的风格的title是透明的
			// Reset next title.
			nextTitle.style.opacity = 0;
			// Switch current class.
			// 设置即将进入的元素类名是当前风格的
			nextSlide.classList.add('slide--current');
			// Animate next slide in.
			// 动画让其进入
			anime(animeInProps);
			// Animate next title in.
			// 让标题进入
			self._animateTitle(nextTitle, 'in');
		};

		// 3. 针对要出去的元素的动画
		// currentSlide.querySelectorAll('.slide-imgwrap .slide__img-inner'):动画中要出去的所有的图片
		// currentSlide:当前要出去的元素
		var outItems = [].slice.call(currentSlide.querySelectorAll('.slide-imgwrap .slide__img-inner')),
			// 获取相关配置参数
			outconfig = this.options.layoutConfig[currentLayout] !== undefined ? this.options.layoutConfig[currentLayout].out : this.options.layoutConfig['layout1'].out,
			animeOutProps = {
				targets: outItems,
				duration: outconfig.duration,
				easing: outconfig.easing,
				// 延迟是一个方法
				delay: function (el, index) {
					return direction === 'next' ? index * outconfig.itemsDelay : (outItems.length - 1 - index) * outconfig.itemsDelay;
				},
				// 走的这个元素之前是添加了一个类名,现在走了要把类名拿掉
				complete: function () {
					currentSlide.classList.remove('slide--current');
				}
			};
		this._setAnimationProperties(animeOutProps, outconfig, direction)
		// 参数传入,直接进行动画
		anime(animeOutProps);
		// 标题
		this._anmateTitle(currentTitle, 'out');
		// 创建定时器:当前风格出去了,再让下一个风格进来
		clearTimeout(this.navtime);
		// animateIn:让动画进来  
		this.navtime = setTimeout(animateIn, this.options.layoutConfig[nextLayout] !== undefined && this.options.layoutConfig[nextLayout].in.delay !== undefined ? this.options.layoutConfig[nextLayout].in.delay : 150);
	}

6、图片进入和出去相关的动画参数——options

这里有7个动画效果,我们只分析一个,其他7个是完全一样的,详细看源码。

	// 图片进入和出去相关的动画参数
	// 设计风格动画参数
	MLSlideshow.prototype.options = {
		// 起始的下标设置成0
		startIdx: 0,
		// layoutConfig:7个风格会放在一个对象下 
		layoutConfig: {
			layout1: {
				// 退出时
				out: {
					// 点击next还是点击prev,方向是不一样的
					translateX: {
						next: '-100%',
						prev: '100%'
					},
					rotateZ: {
						next: function (el, index) {
							return anime.random(-15, 0);
						},
						prev: function (el, index) {
							return anime.random(0, 15);
						}
					},
					opacity: 0,
					duration: 1200,
					easing: 'easeOutQuint',
					itemsDelay: 80
				},
				// 进入时
				in: {
					// resetProps:在进入时需要重置一下动画的参数
					resetProps: {
						translateX: {
							next: '100%',
							prev: '-100%'
						},
						rotateZ: {
							next: function (el, index) {
								return anime.random(0, 15);
							},
							prev: function (el, index) {
								return anime.random(-15, 0);
							}
						},
						opacity: 0,
					},
					translateX: '0%',
					rotateZ: 0,
					opacity: 1,
					duration: 700,
					easing: 'easeOutQuint',
					itemsDelay: 80
				}
			},
            layout12: {
            }
            ...
        }
    }

7、进入和出去两个动画之前都是处理一下参数,把config的参数传递给当前动画的参数,思路和初始化的思路是一样的。

// 处理参数
	MLSlideshow.prototype._setAnimationProperties = function (props, config, direction) {
		var self = this;
		if (config.translateX !== undefined) {
			props.translateX = typeof config.translateX === 'object' ?
				function (el, index) {
					return typeof config.translateX[direction] === 'function' ?
						self._getValuePercentage(config.translateX[direction](el, index), 'width')
						: self._getValuePercentage(config.translateX[direction], 'width');
				} : this._getValuePercentage(config.translateX, 'width');
		}
		if (config.translateY !== undefined) {
			props.translateY = typeof config.translateY === 'object' ? function (el, index) {
				return typeof config.translateY[direction] === 'function' ? self._getValuePercentage(config.translateY[direction](el, index), 'width') : self._getValuePercentage(config.translateY[direction], 'height');
			} : this._getValuePercentage(config.translateY, 'height');
		}
		if (config.rotateZ !== undefined) {
			props.rotateZ = typeof config.rotateZ === 'object' ? function (el, index) {
				return typeof config.rotateZ[direction] === 'function' ? config.rotateZ[direction](el, index) : config.rotateZ[direction];
			} : config.rotateZ;
		}
		if (config.scale !== undefined) {
			props.scale = typeof config.scale === 'object' ? function (el, index) {
				return typeof config.scale[direction] === 'function' ? config.scale[direction](el, index) : config.scale[direction];
			} : config.scale;
		}
		if (config.opacity !== undefined) {
			props.opacity = config.opacity;
		}
	};
    // _getValuePercentage :获取百分比,改为值
	MLSlideshow.prototype._getValuePercentage = function (str, axis) {
		return typeof str === 'string' && str.indexOf('%') !== -1 ? parseFloat(str) / 100 * this.dimentions[axis] : str;
	}

8、设置title动画

// 设置title动画
	MLSlideshow.prototype._anmateTitle = function (titleEl, dir) {
		anime({
			targets: titleEl,
			opacity: dir === 'out' ? 0 : 1,
			duration: dir === 'out' ? 200 : 500,
			easing: 'easeOutExpo'
		})
	}
	MLSlideshow.prototype.next = function () {
		this._navigate('next');
	}
	MLSlideshow.prototype.prev = function () {
		this._navigate('prev');
	}
	window.MLSlideshow = MLSlideshow;

代码就完成了,我们去index.html调用我们写的方法:

<script src="js/imagesloaded.pkgd.min.js"></script>
<script src="js/anime.min.js"></script>
<script src="js/main.js"></script>
<script>
        (function () {
            var slideshow = new MLSlideshow(document.querySelector('.slideshow'));
            document.querySelector('#prev-slide').addEventListener('click', function () {
                slideshow.prev();
            })
            document.querySelector('#next-slide').addEventListener('click', function () {
                slideshow.next();
            })
        })()

</script>

三、完整代码:

// ▷main.js

// 所有代码都是自执行函数
; (function (window) {
	// 严格模式下
	'use strict';
	// extend:把某一个对象的属性复制给另一个对象,把b的属性给a
	function extend(a, b) {
		for (var key in b) {
			if (b.hasOwnProperty(key)) {
				a[key] = b[key];
			}
		}
		return a;
	}
	// 防抖:我们不希望当快速点击的时候我们就一直在执行。想要间隔一定的时间在去触发 
	function debounce(func, wait) {
		var timeout;
		return function () {
			var context = this, args = arguments;
			var later = function () {
				timeout = null;
				func.apply(context, args);
			};
			clearTimeout(timeout);
			timeout = setTimeout(later, wait);
		};
	};

	function MLSlideshow(el, options) {
		// 1. 元素属性
		// 拿到元素,就把元素挂载到对象下
		this.el = el;
		// 2. 相关参数
		this.options = extend({}, this.options);
		extend(this.options, options);
		// 3. 所有照片的风格
		// 最外层盒子取到所有风格的类名
		this.slides = [].slice.call(this.el.querySelectorAll('.slide'));

		// 判断:如果当前照片风格少于2,不创建实例
		this.slidesTotal = this.slides.length;
		if (this.slidesTotal <= 1) {
			return;
		}
		// 4. 当前展示的风格的下标
		this.current = this.options.startIdx || 0;
		// 5. 当前窗口
		this.dimentions = {
			width: this.el.offsetWidth,
			height: this.el.offsetHeight
		}
		// 6. 照片风格初始化
		this._init();
	}

	// 照片墙初始化
	MLSlideshow.prototype._init = function () {
		var self = this, // self保存一下当前的this
			// 1. 当图片加载完成,展示当前第一个风格————由current决定是第几个风格
			// onPreload:图片加载完成要做的事情
			onPreload = function () {
				// 给当前的图片添加一个类名
				self.el.classList.add('slideshow--loaded');
				// 让第一个风格展示
				self.slides[self.current].classList.add('slide--current');
			};
		// 在图片加载完成的时候调用
		this._preload(onPreload);
		// 2. 添加事件:
		// _initEvents独立出一个方法
		this._initEvents();

	}

	// 判断图片是否加载完成
	MLSlideshow.prototype._preload = function (callback) {
		// imagesLoaded直接调用,因为我们已经引入了这个包
		imagesLoaded(this.el, { background: true }, function () {
			// 如果传入的回调是一个函数,我们就去调用它
			if (typeof callback === 'function') {
				callback();
			}
		});
	};

	MLSlideshow.prototype._initEvents = function () {
		var self = this;
		// 2.1 窗口大小事件
		// 用到防抖debounce
		this.debounceResize = debounce(function (ev) {
			self.dimentions = {
				width: self.el.offsetWidth,
				height: self.el.offsetHeight
			};
		}, 10)
		// 添加事件,当窗口的大小发送改变: 
		window.addEventListener('resize', this.debounceResize);
		// 2.2 键盘触发切换风格事件
		// 按下左右键的键盘按键,触发切换的按钮
		this.keyboardFn = function (ev) {
			var keyCode = ev.keyCode || ev.which;
			switch (keyCode) {
				case 37:
					// _navigate('prev'):往前切换
					self._navigate('prev');
					break;
				case 39:
					// _navigate('next'):往后切换
					self._navigate('next');
					break;
			}
		};
		this.el.addEventListener('keydown', this.keyboardFn);
	}
	
	// 图片进入和出去相关的动画参数
	// 设计风格动画参数
	MLSlideshow.prototype.options = {
		// 起始的下标设置成0
		startIdx: 0,
		// layoutConfig:7个风格会放在一个对象下 
		layoutConfig: {
			layout1: {
				// 退出时
				out: {
					// 点击next还是点击prev,方向是不一样的
					translateX: {
						next: '-100%',
						prev: '100%'
					},
					rotateZ: {
						next: function (el, index) {
							return anime.random(-15, 0);
						},
						prev: function (el, index) {
							return anime.random(0, 15);
						}
					},
					opacity: 0,
					duration: 1200,
					easing: 'easeOutQuint',
					itemsDelay: 80
				},
				// 进入时
				in: {
					// resetProps:在进入时需要重置一下动画的参数
					resetProps: {
						translateX: {
							next: '100%',
							prev: '-100%'
						},
						rotateZ: {
							next: function (el, index) {
								return anime.random(0, 15);
							},
							prev: function (el, index) {
								return anime.random(-15, 0);
							}
						},
						opacity: 0,
					},
					translateX: '0%',
					rotateZ: 0,
					opacity: 1,
					duration: 700,
					easing: 'easeOutQuint',
					itemsDelay: 80
				}
			},
			layout2: {
				out: {
					translateX: {
						next: function (el, index) {
							return anime.random(-50, 50) + '%';
						},
						prev: function (el, index) {
							return anime.random(-50, 50) + '%';
						}
					},
					translateY: {
						next: function (el, index) {
							return anime.random(-50, 50) + '%';
						},
						prev: function (el, index) {
							return anime.random(-50, 50) + '%';
						}
					},
					opacity: 0,
					duration: 1200,
					easing: 'easeOutQuint',
					itemsDelay: 10
				},
				in: {
					resetProps: {
						translateX: {
							next: '100%',
							prev: '-100%'
						},
						rotateZ: {
							next: function (el, index) {
								return anime.random(0, 90);
							},
							prev: function (el, index) {
								return anime.random(-90, 0);
							}
						},
						opacity: 0,
					},
					translateX: '0%',
					rotateZ: 0,
					opacity: 1,
					duration: 900,
					easing: 'easeOutExpo',
					itemsDelay: 30
				}
			},
			layout3: {
				out: {
					translateX: '-10%',
					rotateZ: 0,
					opacity: 0,
					duration: 500,
					easing: 'easeOutExpo',
					itemsDelay: 0
				},
				in: {
					resetProps: {
						translateX: '-10%',
						rotateZ: 0,
						opacity: 0
					},
					translateX: 0,
					opacity: 1,
					rotateZ: {
						next: function (el, index) {
							return index * 6;
						},
						prev: function (el, index) {
							return index * 6;
						}
					},
					duration: 1200,
					easing: 'easeOutElastic',
					itemsDelay: 0
				}
			},
			layout4: {
				out: {
					translateY: {
						next: '60%',
						prev: '-60%'
					},
					opacity: 0,
					duration: 700,
					easing: 'easeOutQuint',
					itemsDelay: 50
				},
				in: {
					resetProps: {
						translateY: {
							next: '-60%',
							prev: '60%'
						},
						opacity: 0,
					},
					translateY: '0%',
					opacity: 1,
					duration: 700,
					easing: 'easeOutQuint',
					itemsDelay: 50,
					delay: 250
				}
			},
			layout5: {
				out: {
					scale: 0.5,
					opacity: 0,
					duration: 500,
					easing: 'easeOutExpo',
					itemsDelay: 20
				},
				in: {
					resetProps: {
						scale: 0.5,
						opacity: 0
					},
					opacity: 1,
					scale: 1,
					duration: 500,
					easing: 'easeOutExpo',
					itemsDelay: 20,
					delay: 300
				}
			},
			layout6: {
				out: {
					scale: 0.5,
					opacity: 0,
					duration: 300,
					easing: 'easeInBack',
					itemsDelay: 20
				},
				in: {
					resetProps: {
						scale: 0.5,
						opacity: 0
					},
					opacity: 1,
					scale: 1,
					duration: 1000,
					easing: 'easeOutElastic',
					itemsDelay: 50,
					delay: 400
				}
			},
			layout7: {
				out: {
					translateX: {
						next: '-100%',
						prev: '100%'
					},
					opacity: 0,
					duration: 1200,
					easing: 'easeOutQuint',
					itemsDelay: 40
				},
				in: {
					resetProps: {
						translateX: {
							next: '100%',
							prev: '-100%'
						},
						rotateZ: {
							next: function (el, index) {
								return anime.random(0, 25);
							},
							prev: function (el, index) {
								return anime.random(-25, 0);
							}
						},
						opacity: 0,
					},
					translateX: '0%',
					rotateZ: 0,
					opacity: 1,
					duration: 700,
					easing: 'easeOutQuint',
					itemsDelay: 40,
					delay: 250
				}
			}
		}
	};

	// _navigate:参数接收prev和next
	MLSlideshow.prototype._navigate = function (direction) {
		// isAnimating:判断当前动画是否在运动
		if (this.isAnimating) {
			return false;
		}
		this.isAnimating = true;
		// 1. 获取当前展示风格的信息: 当前元素,唯一标识,相关标题
		var self = this,
			// 知道当前展示的下标是什么也就是要出去的元素,当点击前后切换的时候,改变下标的值来完成
			currentSlide = this.slides[this.current],
			// 获取当前风格标识
			currentLayout = currentSlide.getAttribute('data-layout') || 'layout1',
			// 获取当前展示风格的标题
			currentTitle = currentSlide.querySelector('.slide__title');

		// 2. 获取下一个要展示风格的信息: 当前元素,唯一标识,相关标题
		if (direction === 'next') {
			this.current = this.current < this.slidesTotal - 1 ? this.current + 1 : 0;
		}
		else {
			this.current = this.current > 0 ? this.current - 1 : this.slidesTotal - 1;
		}
		// 获取元素信息
		var nextSlide = this.slides[this.current],
			nextLayout = nextSlide.getAttribute('data-layout'),
			nextTitle = nextSlide.querySelector('.slide__title');
		// 4. 针对要显示的风格创建方法
		var animateIn = function () {

			// 开启动画之前把其他动画停掉
			clearTimeout(self.navtime);

			// 获取计算的要进入的风格的照片元素
			var inItems = [].slice.call(nextSlide.querySelectorAll('.slide-imgwrap .slide__img-inner')),
				// 设置计算的下一个的下标元素动画,如果不存在就设置第一个元素动画,标识区分
				// 获取即将进入的风格的动画参数
				inconfig = self.options.layoutConfig[nextLayout] !== undefined ? self.options.layoutConfig[nextLayout].in : self.options.layoutConfig['layout1'].in,
				// 进入时,初始化设置赋值给inresetconfig
				inresetconfig = inconfig.resetProps,
				// 设置动画参数
				animeInProps = {
					targets: inItems,
					duration: inconfig.duration,
					easing: inconfig.easing,
					delay: function (el, index) {
						return direction === 'next' ? index * inconfig.itemsDelay : (inItems.length - 1 - index) * inconfig.itemsDelay;
					},
					// 动画完成设置动画运动标识是false
					complete: function () {
						self.isAnimating = false;
					}
				};

			// Configure the animation in properties.
			// 将动画参数,当前动画元素相关信息,前后传入设置动画属性的方法中
			self._setAnimationProperties(animeInProps, inconfig, direction);
			// Reset before animating in:
			// 在动画之前重置即将进入的风格的图片
			// 需要重置的原因:因为图片的宽高是相对窗口的 ,但是图片的宽高又是根据浏览器窗口的,所以每一次我们都要重置一下图片的宽高,避免窗口发生改变之后,盒子小了图片还很大这种不好的效果
			inItems.forEach(function (item, pos) {
				var transformStr = '';
				// 将属性中的translateX、translateY、rotateZ、scale、opacity进行重置
				if (inresetconfig.translateX !== undefined) {
					var tx = typeof inresetconfig.translateX === 'object' ?
						function () {
							return typeof inresetconfig.translateX[direction] === 'function' ?
								self._getValuePercentage(inresetconfig.translateX[direction](item, pos), 'width') :
								self._getValuePercentage(inresetconfig.translateX[direction], 'width');
						} : self._getValuePercentage(inresetconfig.translateX, 'width');

					transformStr += ' translateX(' + (typeof tx === 'function' ? tx() : tx) + 'px)';
				}
				if (inresetconfig.translateY !== undefined) {
					var ty = typeof inresetconfig.translateY === 'object' ? function () {
						return typeof inresetconfig.translateY[direction] === 'function' ? self._getValuePercentage(inresetconfig.translateY[direction](item, pos), 'height') : self._getValuePercentage(inresetconfig.translateY[direction], 'height');
					} : self._getValuePercentage(inresetconfig.translateY, 'height');
					transformStr += ' translateY(' + (typeof ty === 'function' ? ty() : ty) + 'px)';
				}
				if (inresetconfig.rotateZ !== undefined) {
					var rot = typeof inresetconfig.rotateZ === 'object' ? function () {
						return typeof inresetconfig.rotateZ[direction] === 'function' ? inresetconfig.rotateZ[direction](item, pos) : inresetconfig.rotateZ[direction];
					} : inresetconfig.rotateZ;

					transformStr += ' rotateZ(' + (typeof rot === 'function' ? rot() : rot) + 'deg)';
				}
				if (inresetconfig.scale !== undefined) {
					var s = typeof inresetconfig.scale === 'object' ? function () {
						return typeof inresetconfig.scale[direction] === 'function' ? inresetconfig.scale[direction](item, pos) : inresetconfig.scale[direction];
					} : inresetconfig.scale;

					transformStr += ' scale(' + (typeof s === 'function' ? s() : s) + ')';
				}
				if (transformStr !== '') {
					item.style.transform = item.style.WebkitTransform = transformStr;
				}
				if (inresetconfig.opacity !== undefined) {
					item.style.opacity = inresetconfig.opacity;
				}
			});
			// 设置即将进入的风格的title是透明的
			// Reset next title.
			nextTitle.style.opacity = 0;
			// Switch current class.
			// 设置即将进入的元素类名是当前风格的
			nextSlide.classList.add('slide--current');
			// Animate next slide in.
			// 动画让其进入
			anime(animeInProps);
			// Animate next title in.
			// 让标题进入
			self._anmateTitle(nextTitle, 'in');
		};

		// 3. 针对要出去的元素的动画
		// currentSlide.querySelectorAll('.slide-imgwrap .slide__img-inner'):动画中要出去的所有的图片
		// currentSlide:当前要出去的元素
		var outItems = [].slice.call(currentSlide.querySelectorAll('.slide-imgwrap .slide__img-inner')),
			// 获取相关配置参数
			outconfig = this.options.layoutConfig[currentLayout] !== undefined ? this.options.layoutConfig[currentLayout].out : this.options.layoutConfig['layout1'].out,
			animeOutProps = {
				targets: outItems,
				duration: outconfig.duration,
				easing: outconfig.easing,
				// 延迟是一个方法
				delay: function (el, index) {
					return direction === 'next' ? index * outconfig.itemsDelay : (outItems.length - 1 - index) * outconfig.itemsDelay;
				},
				// 走的这个元素之前是添加了一个类名,现在走了要把类名拿掉
				complete: function () {
					currentSlide.classList.remove('slide--current');
				}
			};
		this._setAnimationProperties(animeOutProps, outconfig, direction)
		// 参数传入,直接进行动画
		anime(animeOutProps);
		// 标题
		this._anmateTitle(currentTitle, 'out');
		// 创建定时器:当前风格出去了,再让下一个风格进来
		clearTimeout(this.navtime);
		// animateIn:让动画进来  
		this.navtime = setTimeout(animateIn, this.options.layoutConfig[nextLayout] !== undefined && this.options.layoutConfig[nextLayout].in.delay !== undefined ? this.options.layoutConfig[nextLayout].in.delay : 150);
	}

	// 处理参数
	MLSlideshow.prototype._setAnimationProperties = function (props, config, direction) {
		var self = this;
		if (config.translateX !== undefined) {
			props.translateX = typeof config.translateX === 'object' ?
				function (el, index) {
					return typeof config.translateX[direction] === 'function' ?
						self._getValuePercentage(config.translateX[direction](el, index), 'width')
						: self._getValuePercentage(config.translateX[direction], 'width');
				} : this._getValuePercentage(config.translateX, 'width');
		}
		if (config.translateY !== undefined) {
			props.translateY = typeof config.translateY === 'object' ? function (el, index) {
				return typeof config.translateY[direction] === 'function' ? self._getValuePercentage(config.translateY[direction](el, index), 'width') : self._getValuePercentage(config.translateY[direction], 'height');
			} : this._getValuePercentage(config.translateY, 'height');
		}
		if (config.rotateZ !== undefined) {
			props.rotateZ = typeof config.rotateZ === 'object' ? function (el, index) {
				return typeof config.rotateZ[direction] === 'function' ? config.rotateZ[direction](el, index) : config.rotateZ[direction];
			} : config.rotateZ;
		}
		if (config.scale !== undefined) {
			props.scale = typeof config.scale === 'object' ? function (el, index) {
				return typeof config.scale[direction] === 'function' ? config.scale[direction](el, index) : config.scale[direction];
			} : config.scale;
		}
		if (config.opacity !== undefined) {
			props.opacity = config.opacity;
		}
	};

	
	MLSlideshow.prototype._getValuePercentage = function (str, axis) {
		return typeof str === 'string' && str.indexOf('%') !== -1 ? parseFloat(str) / 100 * this.dimentions[axis] : str;
	}

	// 设置title动画
	MLSlideshow.prototype._anmateTitle = function (titleEl, dir) {
		anime({
			targets: titleEl,
			opacity: dir === 'out' ? 0 : 1,
			duration: dir === 'out' ? 200 : 500,
			easing: 'easeOutExpo'
		})
	}
	MLSlideshow.prototype.next = function () {
		this._navigate('next');
	}
	MLSlideshow.prototype.prev = function () {
		this._navigate('prev');
	}
	window.MLSlideshow = MLSlideshow;
})(window)
// ▷index.html

<!DOCTYPE html>
<html lang="en" class="no-js">

<head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>照片墙</title>
    <link rel="stylesheet" type="text/css" href="css/normalize.css" />
    <link rel="stylesheet" type="text/css" href="css/demo.css" />
    <link rel="stylesheet" type="text/css" href="css/slideshow.css" />
    <link rel="stylesheet" type="text/css" href="css/slideshow_layouts.css" />
    <!--[if IE]>
  		<script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
  		<style>
			.ie-message { display: inline-block; }
  		</style>
		<![endif]-->
    <script>document.documentElement.className = 'js';</script>
</head>

<body>
    <svg class="hidden">
        <defs>
            <symbol id="icon-arrow" viewBox="0 0 24 24">
                <title>arrow</title>
                <polygon points="6.3,12.8 20.9,12.8 20.9,11.2 6.3,11.2 10.2,7.2 9,6 3.1,12 9,18 10.2,16.8 " />
            </symbol>
            <symbol id="icon-drop" viewBox="0 0 24 24">
                <title>drop</title>
                <path
                    d="M12,21c-3.6,0-6.6-3-6.6-6.6C5.4,11,10.8,4,11.4,3.2C11.6,3.1,11.8,3,12,3s0.4,0.1,0.6,0.3c0.6,0.8,6.1,7.8,6.1,11.2C18.6,18.1,15.6,21,12,21zM12,4.8c-1.8,2.4-5.2,7.4-5.2,9.6c0,2.9,2.3,5.2,5.2,5.2s5.2-2.3,5.2-5.2C17.2,12.2,13.8,7.3,12,4.8z" />
                <path
                    d="M12,18.2c-0.4,0-0.7-0.3-0.7-0.7s0.3-0.7,0.7-0.7c1.3,0,2.4-1.1,2.4-2.4c0-0.4,0.3-0.7,0.7-0.7c0.4,0,0.7,0.3,0.7,0.7C15.8,16.5,14.1,18.2,12,18.2z" />
            </symbol>
            <symbol id="icon-prev" viewBox="0 0 100 50">
                <title>prev</title>
                <polygon
                    points="5.4,25 18.7,38.2 22.6,34.2 16.2,27.8 94.6,27.8 94.6,22.2 16.2,22.2 22.6,15.8 18.7,11.8" />
            </symbol>
            <symbol id="icon-next" viewBox="0 0 100 50">
                <title>next</title>
                <polygon
                    points="81.3,11.8 77.4,15.8 83.8,22.2 5.4,22.2 5.4,27.8 83.8,27.8 77.4,34.2 81.3,38.2 94.6,25 " />
            </symbol>
            <symbol id="icon-octicon" viewBox="0 0 24 24">
                <title>octicon</title>
                <path
                    d="M12,2.2C6.4,2.2,1.9,6.7,1.9,12.2c0,4.4,2.9,8.2,6.9,9.6c0.5,0.1,0.7-0.2,0.7-0.5c0-0.2,0-0.9,0-1.7c-2.8,0.6-3.4-1.4-3.4-1.4C5.6,17.1,5,16.8,5,16.8C4.1,16.2,5,16.2,5,16.2c1,0.1,1.5,1,1.5,1c0.9,1.5,2.4,1.1,2.9,0.8c0.1-0.7,0.4-1.1,0.6-1.3c-2.2-0.3-4.6-1.1-4.6-5c0-1.1,0.4-2,1-2.7C6.5,8.8,6.2,7.7,6.7,6.4c0,0,0.8-0.3,2.8,1C10.3,7.2,11.1,7.1,12,7c0.9,0,1.7,0.1,2.5,0.3c1.9-1.3,2.8-1,2.8-1c0.5,1.4,0.2,2.4,0.1,2.7c0.6,0.7,1,1.6,1,2.7c0,3.9-2.4,4.7-4.6,5c0.4,0.3,0.7,0.9,0.7,1.9c0,1.3,0,2.4,0,2.8c0,0.3,0.2,0.6,0.7,0.5c4-1.3,6.9-5.1,6.9-9.6C22.1,6.7,17.6,2.2,12,2.2z" />
            </symbol>

            <clipPath id="polygon-clip-rhomboid" clipPathUnits="objectBoundingBox">
                <polygon points="0 1, 0.3 0, 1 0, 0.7 1" />
            </clipPath>
        </defs>
    </svg>
    <main>
        <div class="slideshow" tabindex="0">
            <div class="slide slide--layout-1" data-layout="layout1">
                <div class="slide-imgwrap">
                    <div class="slide__img">
                        <div class="slide__img-inner" style="background-image: url(img/1.jpg);"></div>
                    </div>
                    <div class="slide__img">
                        <div class="slide__img-inner" style="background-image: url(img/2.jpg);"></div>
                    </div>
                    <div class="slide__img">
                        <div class="slide__img-inner" style="background-image: url(img/3.jpg);"></div>
                    </div>
                </div>
                <div class="slide__title">
                    <h3 class="slide__title-main">Now or Never</h3>
                    <p class="slide__title-sub">Our battered suitcases were piled on the sidewalk again; we had longer
                        ways to go. But no matter, the road is life. <a href="#">Read more</a></p>
                </div>
            </div>
            <div class="slide slide--layout-2" data-layout="layout2">
                <div class="slide-imgwrap">
                    <div class="slide__img">
                        <div class="slide__img-inner" style="background-image: url(img/6.jpg);"></div>
                    </div>
                    <div class="slide__img">
                        <div class="slide__img-inner" style="background-image: url(img/5.jpg);"></div>
                    </div>
                    <div class="slide__img">
                        <div class="slide__img-inner" style="background-image: url(img/6.jpg);"></div>
                    </div>
                    <div class="slide__img">
                        <div class="slide__img-inner" style="background-image: url(img/7.jpg);"></div>
                    </div>
                    <div class="slide__img">
                        <div class="slide__img-inner" style="background-image: url(img/9.jpg);">
                            <h4 class="slide__img-caption">Today is someday</h4>
                        </div>
                    </div>
                </div>
                <div class="slide__title">
                    <h3 class="slide__title-main">Crazy Breed</h3>
                    <p class="slide__title-sub">There's those thinking more or less less is more. But if less is more
                        how you're keeping score?</p>
                </div>
            </div>

            <div class="slide slide--layout-3" data-layout="layout3">
                <div class="slide-imgwrap">
                    <div class="slide__img">
                        <div class="slide__img-inner" style="background-image: url(img/9.jpg);"></div>
                    </div>
                    <div class="slide__img">
                        <div class="slide__img-inner" style="background-image: url(img/10.jpg);"></div>
                    </div>
                    <div class="slide__img">
                        <div class="slide__img-inner" style="background-image: url(img/11.jpg);"></div>
                    </div>
                    <div class="slide__img">
                        <div class="slide__img-inner" style="background-image: url(img/15.jpg);"></div>
                    </div>
                    <div class="slide__img">
                        <div class="slide__img-inner" style="background-image: url(img/13.jpg);"></div>
                    </div>
                    <div class="slide__img">
                        <div class="slide__img-inner" style="background-image: url(img/14.jpg);"></div>
                    </div>
                    <div class="slide__img">
                        <div class="slide__img-inner" style="background-image: url(img/12.jpg);"></div>
                    </div>
                </div>
                <div class="slide__title">
                    <h3 class="slide__title-main">Safe Harbor</h3>
                    <p class="slide__title-sub">Twenty years from now you will be more disappointed by the things you
                        didn’t do than by the ones you did do.</p>
                </div>
            </div>

            <div class="slide slide--layout-4" data-layout="layout4">
                <div class="slide-imgwrap">
                    <div class="slide__img">
                        <div class="slide__img-inner" style="background-image: url(img/10.jpg);"></div>
                    </div>
                    <div class="slide__img">
                        <div class="slide__img-inner" style="background-image: url(img/8.jpg);"></div>
                    </div>
                    <div class="slide__img">
                        <div class="slide__img-inner" style="background-image: url(img/11.jpg);"></div>
                    </div>
                    <div class="slide__img">
                        <div class="slide__img-inner" style="background-image: url(img/13.jpg);"></div>
                    </div>
                </div>
                <div class="slide__title">
                    <h3 class="slide__title-main">Our Freedom</h3>
                    <p class="slide__title-sub">For to be free is not merely to cast off one's chains, but to live in a
                        way that respects and enhances the freedom of others.</p>
                </div>
            </div>

            <div class="slide slide--layout-5" data-layout="layout5">
                <div class="slide-imgwrap">
                    <div class="slide__img">
                        <div class="slide__img-inner" style="background-image: url(img/small/1.jpg);"></div>
                    </div>
                    <div class="slide__img">
                        <div class="slide__img-inner" style="background-image: url(img/small/2.jpg);"></div>
                    </div>
                    <div class="slide__img">
                        <div class="slide__img-inner" style="background-image: url(img/small/3.jpg);"></div>
                    </div>
                    <div class="slide__img">
                        <div class="slide__img-inner" style="background-image: url(img/small/4.jpg);"></div>
                    </div>
                    <div class="slide__img">
                        <div class="slide__img-inner" style="background-image: url(img/small/5.jpg);"></div>
                    </div>
                    <div class="slide__img">
                        <div class="slide__img-inner" style="background-image: url(img/small/6.jpg);"></div>
                    </div>
                    <div class="slide__img">
                        <div class="slide__img-inner" style="background-image: url(img/small/7.jpg);"></div>
                    </div>
                    <div class="slide__img">
                        <div class="slide__img-inner" style="background-image: url(img/small/8.jpg);"></div>
                    </div>
                    <div class="slide__img">
                        <div class="slide__img-inner" style="background-image: url(img/small/9.jpg);"></div>
                    </div>
                    <div class="slide__img">
                        <div class="slide__img-inner" style="background-image: url(img/small/10.jpg);"></div>
                    </div>
                    <div class="slide__img">
                        <div class="slide__img-inner" style="background-image: url(img/small/11.jpg);"></div>
                    </div>
                    <div class="slide__img">
                        <div class="slide__img-inner" style="background-image: url(img/small/12.jpg);"></div>
                    </div>
                    <div class="slide__img">
                        <div class="slide__img-inner" style="background-image: url(img/small/13.jpg);"></div>
                    </div>
                    <div class="slide__img">
                        <div class="slide__img-inner" style="background-image: url(img/small/14.jpg);"></div>
                    </div>
                    <div class="slide__img">
                        <div class="slide__img-inner" style="background-image: url(img/small/15.jpg);"></div>
                    </div>
                    <div class="slide__img">
                        <div class="slide__img-inner" style="background-image: url(img/small/16.jpg);"></div>
                    </div>
                    <div class="slide__img">
                        <div class="slide__img-inner" style="background-image: url(img/small/17.jpg);"></div>
                    </div>
                    <div class="slide__img">
                        <div class="slide__img-inner" style="background-image: url(img/small/18.jpg);"></div>
                    </div>
                </div>
                <div class="slide__title">
                    <h3 class="slide__title-main">Stopping Time</h3>
                    <p class="slide__title-sub">Emancipate yourselves from mental slavery, none but ourselves can free
                        our minds.</p>
                </div>
            </div>

            <div class="slide slide--layout-6" data-layout="layout6">
                <div class="slide-imgwrap">
                    <div class="slide__img">
                        <div class="slide__img-inner" style="background-image: url(img/14.jpg);"></div>
                    </div>
                    <div class="slide__img">
                        <div class="slide__img-inner" style="background-image: url(img/11.jpg);"></div>
                    </div>
                    <div class="slide__img">
                        <div class="slide__img-inner" style="background-image: url(img/3.jpg);"></div>
                    </div>
                </div>
                <div class="slide__title">
                    <h3 class="slide__title-main">Walk the Walk</h3>
                    <p class="slide__title-sub">The trouble with being in the rat race is that even if you win, you're
                        still a rat.</p>
                </div>
            </div>

            <div class="slide slide--layout-7" data-layout="layout7">
                <div class="slide-imgwrap">
                    <div class="slide__img">
                        <div class="slide__img-inner" style="background-image: url(img/16.jpg);"></div>
                    </div>
                    <div class="slide__img">
                        <div class="slide__img-inner" style="background-image: url(img/1.jpg);"></div>
                    </div>
                    <div class="slide__img">
                        <div class="slide__img-inner" style="background-image: url(img/4.jpg);"></div>
                    </div>
                </div>
                <div class="slide__title">
                    <h3 class="slide__title-main">Caged Birds</h3>
                    <p class="slide__title-sub">They told me to grow roots, instead I grew wings. Birds born in a cage
                        think flying is an illness. </p>
                </div>
            </div>

            <nav class="slideshow__nav slideshow__nav--arrows">
                <button id="prev-slide" class="btn btn--arrow" aria-label="Previous slide"><svg class="icon icon--prev">
                        <use xlink:href="#icon-prev"></use>
                    </svg></button>
                <button id="next-slide" class="btn btn--arrow" aria-label="Next slide"><svg class="icon icon--next">
                        <use xlink:href="#icon-next"></use>
                    </svg></button>
            </nav>
        </div>

    </main>
    <!-- 引入js中的三个包 -->
    <script src="js/imagesloaded.pkgd.min.js"></script>
    <script src="js/anime.min.js"></script>
    <script src="js/main.js"></script>
    <script>
        (function () {
            var slideshow = new MLSlideshow(document.querySelector('.slideshow'));
            document.querySelector('#prev-slide').addEventListener('click', function () {
                slideshow.prev();
            })
            document.querySelector('#next-slide').addEventListener('click', function () {
                slideshow.next();
            })
        })()

    </script>
</body>

</html>
JS+CSS超酷3D照片墙 JS+CSS=>超酷3D照片墙,不下不知道,下了想推荐! 立即下载

相关推荐

使用jquery.fireworks,实现烟花、爱心照片墙、爱心跳动、随机照片墙,可以自定义文字描述

使用jquery.fireworks,实现烟花、爱心照片墙、爱心跳动、随机照片墙,可以自定义文字描述,适用于2.14,520,521情人节表白,最好有一定的html基础,图片需要替换成你自己的,文字描述也替换成你自己的,js,css,html全都是全的,下载下来就能使用。祝你示爱成功!

【Anime.js】——JavaScript动画库:Anime.js——学习笔记

官网定义:anime.js 是一个简便的JS动画库,用法简单而且适用范围广,涵盖CSS,DOM,SVG还有JS的对象,各种带数值属性的东西都可以动起来。

qq_50497708的博客 1万+

Prometheus常用配置介绍

除了 scrape_configs 外,上部还有 global 和 rule_files 部分, 其中 global 中 是 全 局 参 数 , scrape_interval 指 定 全 局 默 认 的 时 间 间 隔 , evaluation_interval 指定告警规则校验的时间间隔,rule_files 指定了告警规 则文件的位置名称。• annotations(注释):它们被用于存储更长的其他信息,例如警报描述 或者链接,注释值也可以被模板化。• alert:告警的名称。

weixin_42886699的博客 2260

js实现照片墙效果

js实现照片墙效果 <script src="underScore.js"></script> <style> *{ margin: 0; padding: 0; border: 0; list-style: none; } html, body,ul{ width: 100%;

qq_41429765的博客 1165

机理模型与数据模型融合的方式

风电场的发电量受到多种因素的影响,包括但不限于风速、温度、空气密度等。尽管这些环境变量可以直接测量并用作模型输入,但它们与发电量之间的关系往往是复杂的非线性关系。通过引入基于物理定律计算出的理论发电量作为额外特征,可以为数据驱动模型提供更丰富的信息,从而提高预测精度。在这个案例中,我们将使用贝茨理论(Betz Limit)来计算风电场的理论发电量,并将其作为一个新的特征添加到数据集中。然后,我们使用增强后的数据集训练一个简单的神经网络模型来进行发电量预测。

金石软件 4806

KEGG两类报错--①No gene can be mapped--②URL ‘https://rest.kegg.jp/link/hsa/pathway‘…

版本问题,重新安装一下clusterProfiler包。网络问题,可以等待之后再试一下(试过不是)(以上可以排除基因不存在的错误因素)

weixin_57699783的博客 2万+

JavaScript动画库:Anime.js

JavaScript动画库:Anime.js

weixin_41897680的博客 9189

SAP 财务接口开发:完全清账 vs 标准过账的 CO-PA(获利能力字段) 赋值全解析(含设计哲学)

用于完全清账场景:用于标准凭证过账/部分清账两者对 CO-PA 数据的传递方式截然不同。本文不仅提供完整的代码实现,更深入解析为什么 SAP 要这样设计——了解设计哲学,才能灵活应对各类需求。完全清账→ 调用,必须在T_FTPOST中传递,其他特征用BSEG-RKE_前缀。标准过账/部分清账→ 调用,在CRITERIA表中传递特征,字段名直接用WERKSARTNR等。SAP 的设计智慧面向不同场景,采用不同机制,各司其职。通过接口抽象,将复杂的 CO-PA 配置逻辑封装在内部,对外提供简洁的调用方式。

Pegasus666的博客 328

html+js做一个照片墙,有四种样子。

先看看效果 效果不错吧!以下是代码(需要完整代码自行提取)HTML主体: css样式 完整版源码链接:链接:https://pan.baidu.com/s/12NaEczVqSUXBMIaUvwhFzw?pwd=b878 提取码:b878

weqireirtotor的博客 3458

beegfs读取文件完整流程分析

读取小于512KB文件数据,小于1s 读取15MB文件数据,花费7秒。

wfzy的博客 835

基于STM32、HAL库的WF162A 11BA T&R气压传感器 驱动程序设计

/ 转换为7位地址。* @param temperature: 存储读取到的温度值(°C)* @param temperature: 存储读取到的温度值(°C)* @param pressure: 存储读取到的压力值(bar)* @param pressure: 存储读取到的压力值(bar)* @param range: 压力范围(bar)

corlin6688的博客 361

HTML实现3D照片旋转墙

html

gs1we1的博客 7203

彻底摆脱文献只能读开头的痛苦!这款文献检索神器真能帮你跨越文献付费限制(附实操演示)

大家是不是有过这样的经历,好不容易通过关键词搜到了和自己主题高度相关的文献,想要快速获取文献信息,推进研究进度,却又因为付费或者需订阅才能下载PDF,而被劝退。粘贴完成后,点击搜索,搜索结果页面会显示这篇文献的相关信息,有的文献有“下载PDF”,有的文献则只有“求助PDF”,不管是哪种情况,直接点击进入;我这里点击的是“下载PDF”,接着它会跳转页面。我用 Book 学术下载过不少付费文献,实测下来 80% 左右的文献,都能通过它的求助方式成功获取到,只有少部分文献等待的时间会稍微久一些或者没办法下载。

qq_64378896的博客 164

js + 绝对定位实现瀑布流照片墙

js + 绝对定位实现照片墙,原理详解,简单易上手

weixin_46015333的博客 1621

Vue3 - Element Plus 树形表格组件 el-table 一键全部展开折叠功能,支持动态数据及懒加载点击父级才去请求的场景,Tree树状表格每行带有children的表格全部收起和折叠!

vue3,element-plus,表格Table组件,el-table,怎样一键展开/收起,一键展开或折叠树形表格,如何通过按钮来实现全部展开,不生效,一键折叠或展开表格,表格children嵌套,带有子集,多级表格,懒加载,动态数据,table表格的children通过后端请求过来的怎么一键展开请求数据呢,表格如何一键展开和折叠,怎么使用,教程,树形数据table全部展开和折叠,一键展开或折叠树形表格,点击展开接口获取数据,toggleRowExpansion,树形表格懒加载与全部折叠,深层多级,复杂,

🏆 前端领域优质创作者 6803

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

一个轻量级、强大的JavaScript动画库:Anime.js

GSAP(GreenSock Animation Platform)是另一个流行的动画库,拥有更多的功能和扩展性。然而,Anime.js在简洁性和学习曲线上更具优势,适合于简单到中等复杂度的动画场景。虽然jQuery也提供了动画效果的功能,但Anime.js在性能和灵活性方面更胜一筹。相比之下,Anime.js更轻量级,且在处理复杂动画时性能更优。使用Anime.js创建动画非常简单。的元素在1秒内从左上角移动到右下角,并且采用了缓动效果。这段代码会使得class为。这段代码会使得class为。

lostdeer 1685

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

利用JS制作抖音同款3D照片墙(three.js)

利用JS制作抖音同款3D照片墙(three.js) 520快到了,跟我一起学习threeJS 用threeJS制作抖音同款3D照片墙 代码我会后续发布在我的GitHub中,有兴趣的小伙伴可以留言喔

qq_40482342的博客 3831

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

【Anime.js】——用Anime.js实现动画效果

第二个动画不是等到第一个动画结束才开始,是在整个时间轴执行30ms之后开始的,设置Number类型的时间偏移量。现在看到的效果就是,它运动完一个点,跑到下一个点的时候就停止了,我们如何让他一直是动态的呢?是用来创建一个虚拟的节点对象,或者说,是用来创建文档碎片节点。它可以包含各种类型的节点,在创建之初是空的。实现自动选点,对该点进行先缩小后放大如何回到比其他点大一点的状态,并以该点从外向内放大。这两个点不是同时执行的,要让他们有一个交错的效果,给第二个动画设置delay。(1)先实现红色小圆点的动画效果。

qq_50497708的博客 2874

✨ Anime.js Animation 天书,参数终极详解 ✨

准备好深入 Anime.js 的核心了吗?我们来一次性拆解anime()函数中所有可用的API参数。这篇就是你的字典,忘了哪个参数是干嘛的,随时回来查!anime()函数通过一个配置对象(Configuration Object)来工作,我们所有的“魔法”都写在这个对象里。

mnlm2077的博客 1300

探索 `anime.js`:一款强大的JavaScript动画库

探索 anime.js:一款强大的JavaScript动画库 【免费下载链接】anime JavaScript animation engine 项目地址: https://gitcode.com/GitHub_Trending/an/anime ...

gitblog_00076的博客 1061

【前端知识】强大的js动画组件anime.js

概览一、基本信息二、主要特点三、主要功能四、使用方法五、示例代码使用举例1. 基本使用2. 复杂动画示例3. 时间线动画示例4. 播放控制示例。

wendao76的专栏 2499

JS/JQuery整齐的照片墙:展示很多宽高不同照片,让每一行中的所有照片高度一样,所有的行的宽度一样

JS/JQuery照片墙:展示很多宽高不同照片,让每一行中的所有照片高度一样,所有的行的宽度一样 实现思路 最终的效果是照片墙的每一行的height都不一样,但是对于每一行的照片,它们的宽度相加是一个固定的值。 要求的值就是每一行的height, 然后会对每一行的照片赋值为height。 设每一行的width为w;共有n张照片,每一个照片i的宽高分别为wi和hi。因为不让照片缩放,所以wi/hi=ki是一个固定的值,需要先求出来。 wi = hi/ki; w1+w2+w3+…+wn = w; 由前两个公式

C573751767的博客 1437

原生JS编写的照片墙效果实例演示特效

&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt; &lt;html xmlns="http://www.w3.org/1999/xhtml"&gt; &lt;head&gt; &l

weixin_34095889的博客 452

利用原生js实现简易照片墙

效果演示 基本布局 <ul id="pic"> <li> <img data-index="0" src="./images/pic1.jpg" alt=""> </li> <li> <img data-index="1" src="./images/pic2.jpg" alt=""> </li>

belle_mei的博客 1183

java照片墙_js实现超酷的照片墙展示效果图附源码下载

这是一个超酷的照片墙展示效果,很多照片结合淡入淡出、旋转、缩放、倾斜及3D效果,照片快速从左侧切入,做旋转3D效果,最后在照片墙上整齐排列,为用户展示了超酷的照片墙展示效果。HTML本文结合实例给大家分享超酷的照片墙效果,该效果依赖jQuery和easing插件,因此首先载入这两个文件。接着,我们在需要展示照片墙的位置放置如下代码:点击看效果CSSCSS定义了照片墙基本样式,照片排列以及按钮样式。...

weixin_35301706的博客 764

原生js实现3D照片墙

效果:1、点击Start View进入照片墙2、只有一张图片是在中间显示,其他图片在中间的图片两侧随机排序,并且随机旋转一定的角度,层级也是随机的哦3、点击上面的导航条,可以让对应的图片在中间显示4、点击中间的图片该照片翻转,显示背面(照片的描述信息)实现过程:1、用数据生成结构(模拟的数据,此处不再提供)2、对所有图片进行排序3、计算两侧图片的随机范围4、控制图片翻转5、控制导航按钮切换图片6、...

冰雪为融的博客 6413
上一篇: 【Anime.js】——Anime.js源码之引擎的理解
下一篇: 【AnimeJs】——仿Animejs徒手实现SVG动画
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值