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

news2024/11/20 3:35:21

目录

一、实现的效果:

二、实现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>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/112262.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【小5聊】C++ 输入矩阵数字,然后回环方式输出

C 输入矩阵数字&#xff0c;然后回环方式输出 1、题目内容 输入 第一行是两个m和n&#xff0c;分别代表矩阵的行数和列数。 第二行开始输入对应矩阵 输出 第二行回转输出。 相邻的两个整数之间用一个空格分开&#xff0c;行尾无空格 样例输入 5 6 4 8 9 4 5 6 1 2 5 6…

控制算法-PID算法总结-从公式原理到参数整定解析

目录 一、控制系统 1.1控制系统的分类 1.2 性能指标 二、PID算法的起源及特点 三、PID应用 四、PID公式原理 五、PID源码 六、PID整定方法 6.1 经验法 6.2 衰减曲线法 6.3 响应曲线法 参考文献&#xff1a; 一、控制系统 1.1控制系统的分类 分为开环控制、闭环控制和…

Java 8 Stream 从入门到进阶——像SQL一样玩转集合

0.阅读完本文你将会 了解Stream的定义和它的特征了解Stream的基础和高阶用法 1. 前言 在我们日常使用Java的过程中&#xff0c;免不了要和集合打交道。对于集合的各种操作有点类似于SQL——增删改查以及聚合操作&#xff0c;但是其方便性却不如SQL。 所以有没有这样一种方式…

【每日一题Day66】LC1754构造字典序最大的合并字符串 | 贪心 双指针模拟

构造字典序最大的合并字符串【LC1754】 You are given two strings word1 and word2. You want to construct a string merge in the following way: while either word1 or word2 are non-empty, choose one of the following options: If word1 is non-empty, append the fir…

10.2、Django入门--前台管理

文章目录1、URLconf 路由管理展示首页2、视图函数处理业务逻辑展示书籍的详细页3、模板管理实现好看的HTML页面3.1 模板引擎配置3.2 模板语法&#xff1a;变量3.3 模板语法: 常用标签3.4 主页与详情页前端HTML设计常用的HTML编写基础标题标签列表标签图片标签链接标签表格标签表…

耗时二周,万字总结Maven简明教程,与君共勉!

什么是Mavne Maven 是一个项目管理工具&#xff0c;它包含了一个项目对象模型 (POM&#xff1a;Project Object Model)&#xff0c;一组标准集合。由于 Maven 使用标准目录布局和默认构建生命周期&#xff0c;开发团队几乎可以立即自动化项目的构建基础设施。在多个开发团队环…

代码随想录训练营第60天|LeetCode 84.柱状图中最大的矩形

LeetCode 84.柱状图中最大的矩形 双指针 注意&#xff0c;双指针解法可行&#xff0c;但是在力扣上提交会超时。 以heights[i]为中心&#xff0c;用两个指针向两边扩散&#xff0c;直到heights[left]和heights[right]小于heights[i]为止&#xff0c;这样就构成了以left和rig…

第11章_数据库的设计规范(理论了解)

第11章_数据库的设计规范 范式 2.3键和相关属性的概念 范式的定义会使用到主键和候选键&#xff0c;数据库中的键(Key)由一个或者多个属性组成。数据表中常用的几种键和属性的定义: 超键︰能唯─标识元组的属性集叫做超键。候选键︰如果超键不包括多余的属性&#xff0c;那…

基于HOG+LBP完成特征工程,基于机器学习模型同时完成人脸识别+表情识别

这周前两天有时间我写了一篇博文&#xff0c;基于LBP和HOG实现人脸好表情特征的提取计算&#xff0c;之后分别训练了人脸识别模型和表情识别模型&#xff0c;在推理阶段实现了单张图像一次性人脸识别和表情识别的计算分析&#xff0c;但这个我前面就说了这个还是间接的实现方式…

关于GC原理和性能调优实践,看这一篇就够了

前言 本文介绍 GC 基础原理和理论&#xff0c;GC 调优方法思路和方法&#xff0c;基于 Hotspot jdk1.8&#xff0c;学习之后你将了解如何对生产系统出现的 GC 问题进行排查解决。 正文 本文的内容主要如下&#xff1a; GC 基础原理&#xff0c;涉及调优目标&#xff0c;GC 事…

Redis原理篇—数据结构

Redis原理篇—数据结构 笔记整理自 b站_黑马程序员Redis入门到实战教程 底层数据结构 动态字符串SDS 我们都知道 Redis 中保存的 Key 是字符串&#xff0c;value 往往是字符串或者字符串的集合。可见字符串是 Redis 中最常用的一种数据结构。 不过 Redis 没有直接使用C语言中…

Python圣诞树

目录 一、前言 二、创意名 三、效果展示 四、实现步骤 五、编码实现 一、前言 一年一度的圣诞节又要来喽~在这么浪漫的节日里怎么能少的了一个浪漫的程序员呢~让我们一起画个圣诞树&#xff0c;送给你喜欢的那个人吧~ 二、创意名 Python浪漫圣诞树&#xff0c;具体源码见&…

嘿ChatGPT,来帮我写代码

最近 ChatGPT 发行了&#xff0c;这是由 OpenAI 开发的AI聊天机器人&#xff0c;专门研究对话。它的目标是使AI系统更自然地与之互动&#xff0c;但是在编写代码时也可以为您提供帮助。您可以让 ChatGPT 做你的编程助理&#xff0c;甚至更多&#xff01;在过去的几天里&#xf…

腾讯云轻量应用服务器使用 SRS 应用镜像搭建个人直播间、视频转播、本地录制!

SRS 是一个开源的流媒体集群&#xff0c;主要应用在直播和 WebRTC&#xff0c;支持 RTMP、WebRTC、HLS、HTTP-FLV 和 SRT 等常用协议。 轻量应用服务器提供了 SRS 应用镜像&#xff0c;使您无需再关注繁杂的部署操作&#xff0c;即可通过该镜像在轻量应用服务器上一键搭建个人…

安卓/华为手机恢复出厂设置后如何恢复照片

绝大多数安卓用户都会经历过手机恢复出厂设置&#xff0c;部分用户可能没有意识到手机恢复出厂设置可能会导致数据丢失。但是&#xff0c;当您在 云盘上进行备份或在设备上进行本地备份时&#xff0c;情况就会有所不同&#xff0c;并且当您将 安卓手机恢复出厂设置时&#xff0…

LeetCode HOT 100 —— 581. 最短无序连续子数组

题目 给你一个整数数组 nums &#xff0c;你需要找出一个 连续子数组 &#xff0c;如果对这个子数组进行升序排序&#xff0c;那么整个数组都会变为升序排序。 请你找出符合题意的 最短 子数组&#xff0c;并输出它的长度。 思路 方法一&#xff1a;双指针 排序 最终目的是让…

大气湍流自适应光学校正算法matlab仿真,包括涡旋光束,大气湍流影响,不同轨道角动量OAM态之间的串扰,校正等

目录 1.算法描述 2.仿真效果预览 3.MATLAB核心程序 4.完整MATLAB 1.算法描述 涡旋光束是一种具有螺旋波前的光束&#xff0c;在涡旋光束中&#xff0c;决定涡旋光束特性的角量子数可以是任意一个自然数&#xff0c;其不同设置所产生的涡旋光束之间存在正交关系。目前&#…

Android NDK 中堆栈日志 add2line 的分析实践

文章目录目的常用的辅助工具分析步骤参考目的 Android NDK 中出现的 crash 日志分析定位&#xff0c;使用 addr2line 对库中定位so 动态库崩溃位置&#xff0c;定位到某个函数的具体的代码行。 常用的辅助工具 add2line&#xff0c;objdump&#xff0c;ndkstack 等等。本文主要…

一文深度揭开Redis的磁盘持久化机制

前言 Redis 是内存数据库&#xff0c;数据都是存储在内存中&#xff0c;为了避免进程退出导致数据的永久丢失&#xff0c;需要定期将 Redis 中的数据以数据或命令的形式从内存保存到本地磁盘。当下次 Redis 重启时&#xff0c;利用持久化文件进行数据恢复。Redis 提供了 RDB 和…

在linux上安装并初始化配置MariaDB支持远程登录

在linux上安装并初始化配置MariaDB支持远程登录一、环境准备二、启动MariaDB三、初始化MariaDB四、配置远程访问五、补充一些额外的MySql用户赋权限的语句一、环境准备 本文环境是Redhat7上自带的MariaDB, 在安装redhat系统时已经自动安装好了&#xff0c;如果需要自行安装的话…