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 相关文章推荐
jquery 插件 任意位置浮动固定层
Dec 25 Javascript
学习ExtJS 访问容器对象
Oct 07 Javascript
用js获取电脑信息(是使用与IE浏览器)
Jan 15 Javascript
JavaScript学习笔记之DOM基础 2.4
Aug 14 Javascript
javascript常用函数(2)
Nov 05 Javascript
基于jquery实现可定制的web在线富文本编辑器附源码下载
Nov 17 Javascript
Boostrap实现的登录界面实例代码
Oct 09 Javascript
详解从Node.js的child_process模块来学习父子进程之间的通信
Mar 27 Javascript
浅谈在react中如何实现扫码枪输入
Jul 04 Javascript
轻量级富文本编辑器wangEditor结合vue使用方法示例
Oct 10 Javascript
vue通过指令(directives)实现点击空白处收起下拉框
Dec 06 Javascript
你或许不知道的一些npm实用技巧
Jul 04 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
实现了一个PHP5的getter/setter基类的代码
2007/02/25 PHP
PHP中数组的分组排序实例
2014/06/01 PHP
PHP内存缓存功能memcached示例
2016/10/19 PHP
JavaScript Event学习第九章 鼠标事件
2010/02/08 Javascript
js使下拉列表框可编辑不止是选择
2013/12/12 Javascript
node.js正则表达式获取网页中所有链接的代码实例
2014/06/03 Javascript
Javascript 赋值机制详解
2014/11/23 Javascript
javascript实现禁止复制网页内容汇总
2015/12/30 Javascript
JSON 对象未定义错误的解决方法
2016/09/29 Javascript
微信小程序 省市区选择器实例详解(附源码下载)
2017/01/05 Javascript
Vue开发中整合axios的文件整理
2017/04/29 Javascript
关于Angular2 + node接口调试的解决方案
2017/05/28 Javascript
微信小程序之GET请求的实例详解
2017/09/29 Javascript
react-redux中connect的装饰器用法@connect详解
2018/01/13 Javascript
Vue中Table组件Select的勾选和取消勾选事件详解
2019/03/19 Javascript
[03:09]DOTA2亚洲邀请赛 LGD战队出场宣传片
2015/02/07 DOTA
python获取标准北京时间的方法
2015/03/24 Python
Tensorflow之Saver的用法详解
2018/04/23 Python
对Python中gensim库word2vec的使用详解
2018/05/08 Python
Python字典创建 遍历 添加等实用基础操作技巧
2018/09/13 Python
Python实现的微信支付方式总结【三种方式】
2019/04/13 Python
windows系统中Python多版本与jupyter notebook使用虚拟环境的过程
2019/05/15 Python
解决jupyter notebook 前面书写后面内容消失的问题
2020/04/13 Python
python 实现波浪滤镜特效
2020/12/02 Python
River Island美国官网:英国高街时尚品牌
2018/09/04 全球购物
Cult Gaia官网:美国生活方式品牌
2019/08/16 全球购物
生产车间主任的个人自我鉴定
2013/10/25 职场文书
党员群众路线对照检查材料思想汇报
2014/09/17 职场文书
2014年人事工作总结范文
2014/11/19 职场文书
三行辞职书范文
2015/02/26 职场文书
英文慰问信范文
2015/03/24 职场文书
家装业务员岗位职责
2015/04/03 职场文书
聋哑人盗窃罪辩护词
2015/05/21 职场文书
安全知识竞赛主持词
2015/06/30 职场文书
电力安全学习心得体会
2016/01/18 职场文书
JS实现扫雷项目总结
2021/05/19 Javascript