ES6实现图片切换特效代码


Posted in Javascript onJanuary 14, 2020

效果图

ES6实现图片切换特效代码

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实现图片切换特效代码,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

Javascript 相关文章推荐
IE event.srcElement和FF event.target 功能比较
Mar 01 Javascript
ExtJS 入门
Oct 29 Javascript
js对象继承之原型链继承实例
Jan 10 Javascript
JS实现方向键切换输入框焦点的方法
Aug 19 Javascript
纯javascript响应式树形菜单效果
Nov 10 Javascript
基于jQuery实现仿51job城市选择功能实例代码
Mar 02 Javascript
jQuery实现的导航动画效果(附demo源码)
Apr 01 Javascript
KnockoutJs快速入门教程
May 16 Javascript
jQuery AJAX timeout 超时问题详解
Jun 21 Javascript
详解Javascript数据类型的转换规则
Dec 12 Javascript
基于LayUI实现前端分页功能的方法
Jul 22 Javascript
vue elementui form表单验证的实现
Nov 11 Javascript
vue项目创建步骤及路由router
Jan 14 #Javascript
JS实现容器模块左右拖动效果
Jan 14 #Javascript
vue实现网络图片瀑布流 + 下拉刷新 + 上拉加载更多(步骤详解)
Jan 14 #Javascript
vue页面加载时的进度条功能(实例代码)
Jan 13 #Javascript
微信小程序canvas截取任意形状的实现代码
Jan 13 #Javascript
js实现列表向上无限滚动
Jan 13 #Javascript
vue 组件销毁并重置的实现
Jan 13 #Javascript
You might like
PHP 和 XML: 使用expat函数(三)
2006/10/09 PHP
用php实现的下载css文件中的图片的代码
2010/02/08 PHP
yii框架源码分析之创建controller代码
2011/06/28 PHP
解析php函数method_exists()与is_callable()的区别
2013/06/21 PHP
PHPExcel读取EXCEL中的图片并保存到本地的方法
2015/02/14 PHP
Yii净化器CHtmlPurifier用法示例(过滤不良代码)
2016/07/15 PHP
ThinkPHP3.2框架操作Redis的方法分析
2019/05/05 PHP
深入解析PHP底层机制及相关原理
2020/12/11 PHP
extjs fckeditor集成代码
2009/05/10 Javascript
js计算页面刷新的次数
2009/07/20 Javascript
js判断选择时间不能小于当前时间的示例代码
2013/09/24 Javascript
$(document).ready(function() {})不执行初始化脚本
2014/06/19 Javascript
JavaScript中的函数模式详解
2015/02/11 Javascript
JavaScript使用pop方法移除数组最后一个元素用法实例
2015/04/06 Javascript
使用递归遍历对象获得value值的实现方法
2016/06/14 Javascript
工作中比较实用的JavaScript验证和数据处理的干货(经典)
2016/08/03 Javascript
p5.js实现斐波那契螺旋的示例代码
2018/03/22 Javascript
JavaScript中concat复制数组方法浅析
2019/01/20 Javascript
Javascript组合继承方法代码实例解析
2020/04/02 Javascript
python文件和目录操作函数小结
2014/07/11 Python
python编写分类决策树的代码
2017/12/21 Python
利用Python如何生成便签图片详解
2018/07/09 Python
python实现多进程代码示例
2018/10/31 Python
Python面向对象思想与应用入门教程【类与对象】
2019/04/12 Python
浅谈matplotlib.pyplot与axes的关系
2020/03/06 Python
python爬虫调度器用法及实例代码
2020/11/30 Python
python爬虫爬取图片的简单代码
2021/01/18 Python
一文读懂python Scrapy爬虫框架
2021/02/24 Python
美国儿童珠宝在线零售商:Loveivy
2019/05/22 全球购物
波兰最大的宠物用品网上商店:FERA.PL
2019/08/11 全球购物
简述网络文件系统NFS,并说明其作用
2016/10/19 面试题
导游的职业规划书范文
2013/12/27 职场文书
双创工作实施方案
2014/03/26 职场文书
抗洪救灾先进集体事迹材料
2014/05/26 职场文书
2014年学校财务工作总结
2014/12/06 职场文书
创业计划书之奶茶店开店方案范本!
2019/08/06 职场文书