ES6实现图片切换特效代码

效果图

demo.html

<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="UTF-8">

<title>Document</title>

</head>

<body>

<script type="text/javascript">

let arr = ["前端", "jquery", "javascript", "html", "css"];

//补充代码

let lis='';

let ul = document.createElement('ul');

function appendHTML( ...innerhtml){

innerhtml.forEach(el => {

let templates = `<li>`+el+`</li>`;

lis+=templates;

});

return lis;

}

appendHTML(...arr);

ul.innerHTML=lis;

document.body.appendChild(ul);

</script>

</body>

</html>

style.css

* {

margin: 0;

padding: 0;

}

body {

background: #fafafa;

background: url('../images/bg.png')

}

::-webkit-scrollbar {

display: none;

}

#wrap {

width: 1065px;

padding-top: 50px;

margin: 0 auto;

padding: 30px;

background: rgb(255, 255, 255);

border-radius: 2px;

margin-top: 100px;

}

/* 整体容器 */

.__Img__container {

font-size: 10px;

}

/* 分类容器 */

.__Img__container .__Img__classify {

/* text-align: center; */

}

/* 分类按钮 */

.__Img__container .__Img__classify .__Img__classify__type-btn {

display: inline-block;

padding: .2em 1em;

font-size: 1.6em;

margin-right: 10px;

cursor: pointer;

border: 1px solid #e95a44;

outline: none;

color: #e95a44;

transition: all .4s;

user-select: none;

border-radius: 2px;

}

/* 激活状态的分类按钮 */

.__Img__container .__Img__classify .__Img__classify__type-btn.__Img__type-btn-active {

background: #e95a44;

/* border: 1px solid #9b59b6; */

color: #fff;

}

/* 所有图片容器 */

.__Img__container .__Img__img-container {

position: relative;

margin-top: 30px;

width: 1005px;

display: flex;

flex-wrap: wrap;

transition: all .6s cubic-bezier(0.77, 0, 0.175, 1);

}

/* 单个图片容器 */

.__Img__container .__Img__img-container figure {

width: 240px;

height: 140px;

position: absolute;

transition: all .6s cubic-bezier(0.77, 0, 0.175, 1);

transform: scale(0, 0);

opacity: 0;

overflow: hidden;

border-radius: 2px;

user-select: none;

}

/* 伪元素遮罩层 */

.__Img__container .__Img__img-container figure::before {

display: block;

position: absolute;

width: 100%;

height: 100%;

top: 0;

left: 0;

z-index: 4;

background: rgba(58, 12, 5, 0.5);

content: ' ';

font-size: 0;

opacity: 0;

transition: all .3s;

cursor: pointer;

}

/* 图片 */

.__Img__container .__Img__img-container figure img {

display: block;

width: 100%;

height: 100%;

transition: all .3s;

}

/* 图片标题 */

.__Img__container .__Img__img-container figure figcaption {

position: absolute;

top: 50%;

left: 50%;

z-index: 7;

opacity: 0;

font-size: 1.5em;

color: rgb(255, 255, 255);

transform: translate(-50%, -50%);

transition: all .3s;

text-align: center;

cursor: pointer;

}

/* 悬停图片的时候标题显示 */

.__Img__container .__Img__img-container figure:hover figcaption {

opacity: 1;

}

.__Img__container .__Img__img-container figure:hover img {

transform: scale(1.1, 1.1);

}

/* 悬停图片的时候遮罩显示 */

.__Img__container .__Img__img-container figure:hover::before {

opacity: 1;

}

.__Img__overlay {

position: fixed;

top: 0;

left: 0;

right: 0;

bottom: 0;

background-color: rgba(0, 0, 0, .8);

display: flex;

justify-content: center;

align-items: center;

opacity: 0;

transition: all .3s;

display: none;

}

.__Img__overlay .__Img__overlay-prev-btn,

.__Img__overlay .__Img__overlay-next-btn {

position: absolute;

width: 50px;

height: 50px;

border-radius: 50%;

border: 2px solid white;

text-align: center;

line-height: 50px;

color: white;

font-size: 2rem;

cursor: pointer;

}

.__Img__overlay .__Img__overlay-prev-btn {

left: 20px;

}

.__Img__overlay .__Img__overlay-next-btn {

right: 20px;

}

.__Img__overlay .__Img__overlay-prev-btn:active,

.__Img__overlay .__Img__overlay-next-btn:active {

background: rgb(241, 241, 241, .4);

}

.__Img__overlay .__Img__overlay-next-btn::after {

content: "N";

}

.__Img__overlay .__Img__overlay-prev-btn::after {

content: "P";

}

.__Img__overlay img {

transform: scale(2, 2);

}

index.js

// 1. 对图片进行分类

// 2. 生成dom元素

// 3. 绑定事件

// 4. 显示到页面上

// 以插件形式完成

(function (window, document) {

let canChange = true;

let curPreviewImgIndex = 0;

// 公共方法集合

const methods = {

// 以数组形式添加子元素

appendChild(parent, ...children) {

children.forEach(el => {

parent.appendChild(el);

});

},

// 选择器

$(selector, root = document) {

return root.querySelector(selector);

},

// 选择多个元素

$$(selector, root = document) {

return root.querySelectorAll(selector);

}

};

// 构造函数

let Img = function(options) {

// 初始化

this._init(options);

// 生成DOM元素

this._createElement();

// 绑定事件

this._bind();

// 显示到页面上

this._show();

}

// 初始化

Img.prototype._init = function({ data, initType, parasitifer }) {

this.types = ['全部']; // 所有的分类

this.all = []; // 所有图片元素

this.classified = {'全部': []}; // 按照类型分类后的图片

this.curType = initType; // 当前显示的图片分类

this.parasitifer = methods.$(parasitifer); // 挂载点

this.imgContainer = null; // 所有图片的容器

this.wrap = null; // 整体容器

this.typeBtnEls = null; // 所有分类按钮组成的数组

this.figures = null; // 所有当前显示的图片组成的数组

// 对图片进行分类

this._classify(data);

//console.log(this.classified);//分类的结果

};

// 对图片进行分类

Img.prototype._classify = function(data) {

let srcs = [];

// 解构赋值,获取每张图片的四个信息

data.forEach(({ title, type, alt, src }) => {

// 如果分类中没有当前图片的分类,则在全部分类的数组中新增该分类

if (!this.types.includes(type)) {

this.types.push(type);

}

// 判断按照类型分类后的图片中有没有当前类型

if (!Object.keys(this.classified).includes(type)) {

this.classified[type] = [];

}

// 判断当前图片是否已生成

if (!srcs.includes(src)) {

// 如果图片没有生成过,则生成图片,并添加到对应的分类中

srcs.push(src);

let figure = document.createElement('figure');

let img = document.createElement('img');

let figcaption = document.createElement('figcaption');

img.src = src;

img.setAttribute('alt', alt);

figcaption.innerText = title;

// 在figure中添加img和figcaption

methods.appendChild(figure, img, figcaption);

// 将生成的figure添加到all数组中

this.all.push(figure);

// 新增的这个图片会在all数组中的最后一个元素

this.classified[type].push(this.all.length - 1);

} else {

// 去all中 找到对应的图片

// 添加到 对应的分类中

this.classified[type].push(srcs.findIndex(s1 => s1 === src));

}

});

};

// 根据分类获取图片

Img.prototype._getImgsByType = function(type) {

// 如果分类是全部,就返回所有图片

// 否则,通过map进行遍历,根据分类来获取图片数组

return type === '全部' ? [...this.all] : this.classified[type].map(index => this.all[index]);

};

// 生成DOM

Img.prototype._createElement = function() {

// 创建分类按钮

let typesBtn = [];

// 遍历分类数组

for (let type of this.types.values()) {

typesBtn.push(`

<li class="__Img__classify__type-btn${ type === this.curType ? ' __Img__type-btn-active' : '' }">${ type }</li>

`);

}

//console.log(typesBtn);//查看所有分类按钮

// 整体的模版

let tamplate = `

<ul class="__Img__classify">

${ typesBtn.join('') }

</ul>

<div class="__Img__img-container"></div>

`;

let wrap = document.createElement('div');

wrap.className = '__Img__container';

wrap.innerHTML = tamplate;//生成整体元素

//取得所有图片的容器

this.imgContainer = methods.$('.__Img__img-container', wrap);

//查看当前分类下的图片

console.log(this._getImgsByType(this.curType));

// 把当前分类下的图片数组,插入到图片容器里

methods.appendChild(this.imgContainer, ...this._getImgsByType(this.curType));

//把可能有用的数据先挂到指定位置

this.wrap = wrap;

this.typeBtnEls = [...methods.$$('.__Img__classify__type-btn', wrap)];

this.figures = [...methods.$$('figure', wrap)];

// 遮罩层

let overlay = document.createElement('div');

overlay.className = '__Img__overlay';

overlay.innerHTML = `

<div class="__Img__overlay-prev-btn"></div>

<div class="__Img__overlay-next-btn"></div>

<img src="" alt="">

`;

// 把遮罩层添加到图片墙中

methods.appendChild(this.wrap, overlay);

this.overlay = overlay;

// 当前要预览的图片

this.previewImg = methods.$('img', overlay);

// 移动每张图片到合适的位置

this._calcPosition(this.figures);

};

// 获取上一次显示的图片和下一次显示的图片中,相同的图片下标(映射关系)

Img.prototype._diff = function(prevImgs, nextImgs) {

let diffArr = [];//保存两次中相同的数据的下标

//遍历前一次的所有图片

//如果在下一次中存在相同的,则获取下标index2

prevImgs.forEach((src1, index1) => {

let index2 = nextImgs.findIndex(src2 => src1 === src2);

if (index2 !== -1) {

// 在这个映射数组中存入下标

diffArr.push([index1, index2]);

}

});

return diffArr;

};

// 绑定事件

Img.prototype._bind = function() {

// 事件代理,点击事件绑定在ul上

methods.$('.__Img__classify', this.wrap).addEventListener('click', ({ target }) => {

if (target.nodeName !== 'LI') return;

if (!canChange) return;

canChange = false;

const type = target.innerText;//获取按钮上的文字(图片类型)

const els = this._getImgsByType(type);//获取对应类型的图片

let prevImgs = this.figures.map(figure => methods.$('img', figure).src);//上一次显示的图片数组

let nextImgs = els.map(figure => methods.$('img', figure).src);//下一次显示的图片数组

const diffArr = this._diff(prevImgs, nextImgs);//获取两次相同图片的映射关系(下标)

diffArr.forEach(([, i2]) => {

// 对下一次的所有图片进行遍历

this.figures.every((figure, index) => {

let src = methods.$('img', figure).src;

// 如果下一次的图片在这一次中已经出现过

if (src === nextImgs[i2]) {

// 则从所有图片数组中剔除该图片(从Index位置,裁剪1个)

this.figures.splice(index, 1);

return false;

}

return true;

});

});

// 计算图片位置

this._calcPosition(els);

let needAppendEls = [];

if (diffArr.length) {

// 如果存在相同图片

let nextElsIndex = diffArr.map(([, i2]) => i2);

els.forEach((figure, index) => {

// 如果该图片没有出现过,则需要插入

if (!nextElsIndex.includes(index)) needAppendEls.push(figure);

});

} else {

// 如果不存在相同图片

needAppendEls = els;//需要插入的图片=所有图片

}

// 上一次的图片全部隐藏掉

this.figures.forEach(el => {

el.style.transform = 'scale(0, 0) translate(0%, 100%)';

el.style.opacity = '0';

});

// 把下一次需要显示的图片添加到图片容器中

methods.appendChild(this.imgContainer, ...needAppendEls);

// 设置下一次显示的动画

setTimeout(() => {

// els表示所有图片,包括新增的,和上一次已经显示过的

els.forEach(el => {

el.style.transform = 'scale(1, 1) translate(0, 0)';

el.style.opacity = '1';

});

});

// 从DOM中销毁上一次出现的图片,将图片数组转为下一次要现实的图片

setTimeout(() => {

this.figures.forEach(figure => {

this.imgContainer.removeChild(figure);

});

this.figures = els;

canChange = true;

// 保证在一次切换动画没有完成之前,拒绝进行下一次切换

// 避免快速切换

}, 600);

// 给图片按钮添加切换时的动画效果

this.typeBtnEls.forEach(btn => (btn.className = '__Img__classify__type-btn'));

target.className = '__Img__classify__type-btn __Img__type-btn-active';

});

// 事件代理实现点击图片的效果

this.imgContainer.addEventListener('click', ({ target }) => {

// 如果点击的不是图片或者图片描述,则返回

if (target.nodeName !== 'FIGURE' && target.nodeName !== 'FIGCAPTION') return;

// 如果点击的是图片的描述

// 则把target转为其父元素图片

if (target.nodeName === 'FIGCAPTION') {

target = target.parentNode;

}

const src = methods.$('img', target).src;

// 拿到当前图片索引

curPreviewImgIndex = this.figures.findIndex(figure => src === methods.$('img', figure).src);

this.previewImg.src = src;//把当前图片的src属性赋值给预览图

this.overlay.style.display = 'flex';//设置遮罩层布局显示

setTimeout(() => {

this.overlay.style.opacity = '1';//设置遮罩层显示

});

});

// 预览时点击遮罩层,实现预览退出

this.overlay.addEventListener('click', () => {

this.overlay.style.opacity = '0';

// 箭头函数可以保留最初的this指向

setTimeout(() => {

this.overlay.style.display = 'none';

}, 300);

});

// 预览点击切换上一张

methods.$('.__Img__overlay-prev-btn', this.overlay).addEventListener('click', e => {

e.stopPropagation();//阻止事件冒泡

// 如果是第一张,上一张就是最后一张

curPreviewImgIndex = curPreviewImgIndex === 0 ? this.figures.length - 1 : curPreviewImgIndex - 1;

// 获取到需要上一张显示的图片的src,赋值给预览图的src

this.previewImg.src = methods.$('img', this.figures[curPreviewImgIndex]).src;

});

// 预览点击切换下一张

methods.$('.__Img__overlay-next-btn', this.overlay).addEventListener('click', e => {

e.stopPropagation();

// 如果是最后一张,下一张就是第一张

curPreviewImgIndex = curPreviewImgIndex === this.figures.length - 1 ? 0 : curPreviewImgIndex + 1;

this.previewImg.src = methods.$('img', this.figures[curPreviewImgIndex]).src;

});

};

// 显示元素

Img.prototype._show = function() {

methods.appendChild(this.parasitifer, this.wrap);

//设置出现的动画效果

setTimeout(() => {

this.figures.forEach(figure => {

figure.style.transform = 'scale(1, 1) translate(0, 0)';

figure.style.opacity = '1';

});

});

};

// 计算每张图片所占的位置

Img.prototype._calcPosition = function(figures) {

let horizontalImgIndex = 0;

figures.forEach((figure, index) => {

figure.style.top = parseInt(index / 4) * 140 + parseInt(index / 4) * 15 + 'px';

figure.style.left = horizontalImgIndex * 240 + horizontalImgIndex * 15 + 'px';

figure.style.transform = 'scale(0, 0) translate(0, -100%)';

horizontalImgIndex = (horizontalImgIndex + 1) % 4;

});

let len = Math.ceil(figures.length / 4);//总行数

this.imgContainer.style.height = len * 140 + (len - 1) * 15 + 'px';//解决绝对定位造成的父容器高度塌陷的问题

};

// 把生成的图片墙挂到全局

window.$Img = Img;

})(window, document);

data.js

// 图片信息文件

const data = [

{

type: 'JavaScript',

title: 'ES6快速入门',

alt: 'ES6快速入门',

src: './assets/images/1.jpg'

},

{

type: 'JavaScript',

title: 'Javascript实现二叉树算法',

alt: 'Javascript实现二叉树算法',

src: './assets/images/2.jpg'

},

{

type: 'JavaScript',

title: 'Canvas绘制时钟',

alt: 'Canvas绘制时钟',

src: './assets/images/3.jpg'

},

{

type: 'JavaScript',

title: '基于websocket的火拼俄罗斯',

alt: '基于websocket的火拼俄罗斯',

src: './assets/images/15.jpg'

},

{

type: '前端框架',

title: 'React知识点综合运用实例',

alt: 'React知识点综合运用实例',

src: './assets/images/4.jpg'

},

{

type: '前端框架',

title: 'React组件',

alt: 'React组件',

src: './assets/images/5.jpg'

},

{

type: '前端框架',

title: 'Vue+Webpack打造todo应用',

alt: 'Vue+Webpack打造todo应用',

src: './assets/images/6.jpg'

},

{

type: '前端框架',

title: 'Vue.js入门基础',

alt: 'Vue.js入门基础',

src: './assets/images/7.jpg'

},

{

type: '前端框架',

title: '使用Vue2.0实现购物车和地址选配功能',

alt: '使用Vue2.0实现购物车和地址选配功能',

src: './assets/images/8.jpg'

},

{

type: 'React',

title: 'React知识点综合运用实例',

alt: 'React知识点综合运用实例',

src: './assets/images/4.jpg'

},

{

type: 'React',

title: 'React组件',

alt: 'React组件',

src: './assets/images/5.jpg'

},

{

type: 'Vue.js',

title: 'Vue+Webpack打造todo应用',

alt: 'Vue+Webpack打造todo应用',

src: './assets/images/6.jpg'

},

{

type: 'Vue.js',

title: 'Vue.js入门基础',

alt: 'Vue.js入门基础',

src: './assets/images/7.jpg'

},

{

type: 'Vue.js',

title: '使用Vue2.0实现购物车和地址选配功能',

alt: '使用Vue2.0实现购物车和地址选配功能',

src: './assets/images/8.jpg'

}

]

总结

以上所述是小编给大家介绍的ES6实现图片切换特效代码,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对网站的支持!

如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

以上是 ES6实现图片切换特效代码 的全部内容, 来源链接: utcz.com/z/347883.html

回到顶部