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 相关文章推荐
json格式化/压缩工具 Chrome插件扩展版
May 25 Javascript
检测input每次的输入是否合法遇到汉字输入就有问题
May 23 Javascript
JQuery 图片的展开和伸缩实例讲解
Apr 18 Javascript
简单常用的幻灯片播放实现代码
Sep 25 Javascript
javascript 获取元素样式必杀技
May 04 Javascript
基于jQuery实现的旋转彩圈实例
Jun 26 Javascript
4种JavaScript实现简单tab选项卡切换的方法
Jan 06 Javascript
jQuery ajax提交Form表单实例(附demo源码)
Apr 06 Javascript
three.js中3D视野的缩放实现代码
Nov 16 Javascript
探索Vue高阶组件的使用
Jan 08 Javascript
Bootstrap简单实用的表单验证插件BootstrapValidator用法实例详解
Mar 29 Javascript
Vue通过getAction的finally来最大程度避免影响主数据呈现问题
Apr 24 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
《雄兵连》系列首部大电影《烈阳天道》:可能是因为期望值太高了
2020/08/18 国漫
php Xdebug 调试扩展的安装与使用.
2010/03/13 PHP
Laravel 5.5 的自定义验证对象/类示例代码详解
2017/08/29 PHP
PHP结合Vue实现滚动底部加载效果
2017/12/17 PHP
javascript 设置文本框中焦点的位置
2009/11/20 Javascript
Javascript 八进制转义字符(8进制)
2011/04/08 Javascript
JS trim去空格的最佳实践
2011/10/30 Javascript
table行随鼠标移动变色示例
2014/05/07 Javascript
关于Javascript 对象(object)的prototype
2014/05/09 Javascript
JS获取单击按钮单元格所在行的信息
2014/06/17 Javascript
AngularJS初始化过程分析(引导程序)
2014/12/06 Javascript
浅谈类似于(function(){}).call()的js语句
2015/03/30 Javascript
jQuery动画效果实现图片无缝连续滚动
2016/01/12 Javascript
纯JavaScript基于notie.js插件实现消息提示特效
2016/01/18 Javascript
jquery实现具有收缩功能的垂直导航菜单
2016/02/16 Javascript
bootstrap table实现x-editable的行单元格编辑及解决数据Empty和支持多样式问题
2017/08/10 Javascript
微信小程序实现点击按钮修改字体颜色功能【附demo源码下载】
2017/12/05 Javascript
Vue2.0 实现页面缓存和不缓存的方式
2019/11/12 Javascript
JavaScript使用百度ECharts插件绘制饼图操作示例
2019/11/26 Javascript
详解vue-router 动态路由下子页面多页共活的解决方案
2019/12/22 Javascript
VUE项目axios请求头更改Content-Type操作
2020/07/24 Javascript
Vue检测屏幕变化来改变不同的charts样式实例
2020/10/26 Javascript
绘制微信小程序验证码功能的实例代码
2021/01/05 Javascript
Python简明入门教程
2015/08/04 Python
对numpy中轴与维度的理解
2018/04/18 Python
Python创建一个空的dataframe,并循环赋值的方法
2018/11/08 Python
python处理“
2019/06/10 Python
Python读取csv文件实例解析
2019/12/30 Python
pytorch 实现张量tensor,图片,CPU,GPU,数组等的转换
2020/01/13 Python
Python把图片转化为pdf代码实例
2020/07/28 Python
Python如何输出百分比
2020/07/31 Python
2014三八妇女节活动总结
2014/03/01 职场文书
校园安全演讲稿
2014/05/09 职场文书
学习作风建设心得体会
2014/10/22 职场文书
人民调解协议书
2016/03/21 职场文书
JavaScript小技巧带你提升你的代码技能
2021/09/15 Javascript