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 相关文章推荐
JavaScript 版本自动生成文章摘要
Jul 23 Javascript
Javascript中的变量使用说明
May 18 Javascript
javascript静态页面传值的三种方法分享
Nov 12 Javascript
一个js导致的jquery失效问题的解决方法
Nov 27 Javascript
JavaScript获取table中某一列的值的方法
May 06 Javascript
javascript编写实用的省市选择器
Feb 12 Javascript
纯javascript移动优先的幻灯片效果
Nov 02 Javascript
node.js学习之事件模块Events的使用示例
Sep 28 Javascript
angular5 httpclient的示例实战
Mar 12 Javascript
vue组件实现可搜索下拉框扩展
Oct 23 Javascript
JavaScript制作3D旋转相册
Aug 02 Javascript
Vue实现点击当前行变色
Dec 14 Vue.js
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的PDF文档生成技术
2006/10/09 PHP
PHP5.2下preg_replace函数的问题
2015/05/08 PHP
PHP编辑器PhpStrom运行缓慢问题
2017/02/21 PHP
php中对象引用和复制实例分析
2019/08/14 PHP
jQuery1.5.1 animate方法源码阅读
2011/04/05 Javascript
网页源代码保护(禁止右键、复制、另存为、查看源文件)
2012/05/23 Javascript
javascript学习笔记(十三) js闭包介绍(转)
2012/06/20 Javascript
关于jquery input textare 事件绑定及用法学习
2013/04/03 Javascript
父页面显示遮罩层弹出半透明状态的dialog
2014/03/04 Javascript
jquery跟js初始化加载的多种方法及区别介绍
2014/04/02 Javascript
JavaScript里四舍五入函数round用法实例
2015/04/06 Javascript
JS控制HTML元素的显示和隐藏的两种方法
2016/09/27 Javascript
jquery获取点击控件的绝对位置简单实例
2016/10/13 Javascript
jQuery实现的简单手风琴效果示例
2018/08/29 jQuery
JavaScript基于遍历操作实现对象深拷贝功能示例
2019/03/05 Javascript
通过seajs实现JavaScript的模块开发及按模块加载
2019/06/06 Javascript
基于JQuery实现页面定时弹出广告
2020/05/08 jQuery
跟老齐学Python之关于类的初步认识
2014/10/11 Python
详解详解Python中writelines()方法的使用
2015/05/25 Python
深入解答关于Python的11道基本面试题
2017/04/01 Python
python正则实现计算器功能
2017/12/14 Python
python使用suds调用webservice接口的方法
2019/01/03 Python
Python 脚本拉取 Docker 镜像问题
2019/11/10 Python
使用卷积神经网络(CNN)做人脸识别的示例代码
2020/03/27 Python
Python字典dict常用方法函数实例
2020/11/09 Python
CSS3 选择器 伪类选择器介绍
2012/01/21 HTML / CSS
为您的家、后院、车库等在线购物:Spreetail
2019/06/17 全球购物
保送生自荐信范文
2013/10/06 职场文书
个人评语大全
2014/05/04 职场文书
学习“七一”讲话精神体会
2014/07/08 职场文书
学校教师安全责任书
2014/07/23 职场文书
党支部群众路线整改措施思想汇报
2014/10/10 职场文书
会计专业求职信范文
2015/03/19 职场文书
律师催款函范文
2015/06/24 职场文书
庆元旦主持词
2015/07/06 职场文书
导游词之泉州崇武古城
2019/12/20 职场文书