原生JS改变透明度实现轮播效果


Posted in Javascript onMarch 24, 2017

在我看来要想实现轮播主要是要知道当前位于的页面和即将位于的页面。这个案例是通过改变图片的透明度来实现轮播的效果。

我把涉及的知识点分为两个方面,分别是HTML+css和JS。

第一部分(html+css)

包含的知识有:positon定位。

最外层是一个div,它包含了所有的元素。这个轮播一共有三张图片,这三张图片包含在一个无序列表中。最外层的div还有两个用来切换上一张图片和下一张图 片的子元素。这两个子元素也是div,切换上一张图片的div的id属性为pre,切换下一张图片的div的id属性为next。最外层div的 position值为relative。包含图片的无序列表的position为relative。无序列表中的li元素的positon属性值为 absolute,这会让li元素位于文档流之外,所以如果不显示的设置ul的高度,ul高度为零。但是我们不能用css去显示设置ul的高度。因为需要 让这个轮播的高度等于图片的高度,并且要保证在不同分辨率的计算机上图片的高宽比保持不变。在不同分辨率的计算机上图片显示出的高度和宽度是不一样的。所 以我是通过js去设置ul的高度。因为ul的position的属性值为relative,所以ul的高度会撑开外层div的高度。由于这个案例是通过改 变图片透明度实现轮播,所以所有的图片位于同一个位置,在默认情况下最后一张图片会在最上面,第一个图片是在最下面,而轮播第一张显示的图片图片应该是第 一张,然后是第二张,最后才是第三张,所以要显示的对每个li设置z—index属性。并且z-index属性值依次递减。我是用js去设置每一个li的 z-index属性值,但其实并没有必要这样做,直接用css属性就可以了,只不过要写三个选择器。

html如下:

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>通过改变透明度实现轮播</title>
 <link rel="stylesheet" type="text/css" href="index.css" rel="external nofollow" >
</head>
<body>
 <div class='warp' id='warp'>
 <ul class='list' id='list'>
  <li><img src='img/4274ad202b27b671e622388989399d54.jpg' style='opacity: 1'></li>
  <li><img src='img/299733ddbe89d6b317cc0e84c43999d4.jpg' style='opacity: 1'></li>
  <li><img src='img/9b7ec36280e638929aa10ce0955df3d3.jpg' style='opacity: 1'></li>
 </ul>
 <div class='pre' id='pre'>《</div>
 <div class='next' id='next'>》</div>
 </div>
 <script type="text/javascript" src='index.js'></script>
</body>
</html>

css代码如下

*{
 padding: 0;
 margin: 0;
}
.warp{
 position: relative;
 width: 100%;
}
.list{
 position: relative;
 width: 100%;
}
.list li{
 position: absolute;
 top:0;
 left: 0;
 width: 100%;
 list-style: none;
 opacity: 1;
}
li img{
 width: 100%;
}
.pre,.next{
 position: absolute;
 top: 50%;
 bottom: 0;
 width: 64px;
 height: 64px;
 z-index: 10;
 margin-top: -32px;
 text-align: center;
 line-height: 64px;
 color: #fff;
 font-weight: bold;
 font-size: 30px;
 cursor: pointer;
 background-color: transparent;
}
.pre{
 left: 20px;
 right: auto;
}
.next{
 right:20px;
 left: auto;
}
.pre:hover,.next:hover{
 background-color: rgba(0,0,0,0.7);
}

第二部分(js)涉及的知识有:事件,函数节流,设置定时器,清除定时器
事件由于用的是原生js去实现功能,所以需要考虑浏览器兼容问题。

事件流

有 两种类型的时间流,分别是事件冒泡流和事件捕获流,这差不多是完全相反的事件流概念,事件冒泡流叫做事件冒泡,这是IE提出的。以一个click事件为 例,在事件冒泡中事件首先发生在最具体的那个元素上,也就是我们单击的那个元素,然后沿着dom树向上传播,在传播的过程中,每一级节点都会发生 click事件,直到传播的document对象。事件捕获流叫做事件捕获,这是由Netscape Communicator提出的。同样以一个 click事件为例,在事件捕获中事件首先发生在最不具体的那个节点上(document对象首先接收到事件),然后沿着dom树向下传播,最具体的节点 最后接收到事件,也就是说,实际上被点击的那个元素最后接收click事件。“DOM2级事件”规定事件流包括三个阶段,分别为事件捕获阶段,处于目标阶 段和事件冒泡阶段。在主流浏览器中除了IE不支持DOM事件流,其他浏览器都支持DOM事件流。所以IE之支持事件冒泡。但是在将来IE应该会支持DOM 事件流。那时候在绑定事件的时候就不用考虑浏览器兼容问题了。目前为了最大程度的兼容各种浏览器,我将事件处理程序添加到事件流的冒泡阶段。

事件处理程序

》DOM0级事件处理程序

DOM0 级使用为元素的属性赋值的方式绑定事件,将事件处理程序属性的值设置为一个函数即可。程序中的this指当前元素。删除通过DOM0级方法绑定的事件方法 是:将事件处理程序的属性设置为null。如果一个元素绑定了事件,在把这个元素移除文档之前,最好手动的的解除这个元素绑定的事件。这样可以防止元素已 经被移除了但是该元素的事件处理程序的引用还保持在内存中。所以的现代浏览器都支持DOM0级事件处理程序。但是用DOM0级绑定事件时,每个元素同一个 事件只能添加一个事件处理程序。

》DOM2级事件处理程序

在“DOM2级事件”中指定事件处理程序的方法为:addEventListener(),第一个参是一个事件名,第二个参数为一个事件处理程序(即一个函 数,可以是匿名函数),第三个参数是一个布尔值。这个布尔值表示在哪一个阶段处理事件,当为false时表示在冒泡阶段处理,当为true时表示在捕获阶 段处理。为了兼容性我将这个值设置为false。解除用“DOM2级事件”绑定的时间处理程序,需要使用removeEventListener(),匿 名的事件处理程序不能被解除。使用“DOM2级事件”绑定事件时,每个元素同一个事件可以添加多个事件处理程序。用“DOM2级事件”绑架的事件处理程 序,this是指当前元素。

》IE事件处理程序

在IE中指定事件处理程序的方法是 attachEvent(),第一个参数是事件处理程序名(即“on”+事件名),第二个参数是时间处理程序(一个函数,可以是匿名函数)。由于IE只支 持事件冒泡所以事件在冒泡阶段处理。使用detachEvent()可以移除用attachEvent()添加的时间处理程序,但是匿名函数不能被移除。 使用attachEvent()绑定事件this指window。。使用attachEvent绑定事件时,每个元素同一个事件可以添加多个事件处理程序。

注:匿名函数不能被移除的原因是:在js中函数是一个对象,这个对象被保存在堆里,函数名是一个指针,指向堆里的对象。对于一个匿名函数而言没有指针指向它,所以就访问不到。

事件对象

在兼容DOM的浏览器中,事件对象是作为一个参数传递到事件处理程序中。(即在兼容DOM的浏览器,不论是通过DOM0级或DOM2级绑定事件,都会将事件 对象作为参数传递到事件处理程序中),当时IE浏览器中,如果用DOM0级指定时间处理程序,事件对象是保存在window的event属性中,如果用 attachEvent()指定时间处理程序,事件对象是作为一个参数传递到事件处理程序中。在兼容DOM的浏览器的事件对象中的值和IE的事件对象中的 值存在差异。但它们都有一个共同的值——type(即:被触发的时间的类型)。在兼容DOM的浏览器中,事件对象的target属性表示事件的目标,以一 个click事件为例,target属性指最具体的那个元素。在IE浏览器中,事件对象的srcElement属性表示事件目标

在这个案例中,我为最外层的div(它的id为warp)添加了一个click的事件处理程序。通过判断事件目标的id值确定触发事件最具体的那个节点。如果事件目 标的id值为pre则切换到上一个图片,如果事件目标的id值为next则切换到下一张图片。这儿用的是事件代理,事件代理可以减少使用的内存。

函数节流在这个案例中使用函数节流是为了减少当连续触发resize事件时浏览器的计算量,因为如果浏览器的计算量太大,浏览器会变慢,甚至崩溃。函数节流的主要思 路是当事件被触发时,在事件处理程序中,并不是立即做计算,而是使用setTimeout或者setInterval在指定的时间后进行计算。

设置定时器和清除定时器由于要完全讲清楚定时器还涉及浏览器线程和js的单线程执行等问题现在不做讲解。主要是我也还没有完全的搞明白。在这里提一下浏览器是多线程的,开启定时器 是在浏览器的定时器线程,js执行程序是在浏览器的另一个线程。浏览器除了这两个线程还没有其他的线程。等我也明白了浏览器线程之间的联系以后我会再写一 篇文章。

在这个实例中改变图片的透明度是通过设置定时器逐渐变大或者逐渐变小。在增加下一张图片的不透明度之前,要先将当前图片的不透名都减小到0。

打开页面自动播放,也是用定时器实现的,如果要停止播放,就清除定时器

js代码如下 

// 当页面加载完成后将所以需要执行的函数添加到window的load事件上。这儿用的是dom0级事件的绑定,所以不能为window的load事件添加 多个事件处理程序,所以使用的方法是:先判断window.onload有没有绑定函数,如果绑定了,就将新的函数追加到尾部,如果没有绑定,就直接添加 给它。用attachEvent()或者addEventListener()可以为同一个元素的同一个事件绑定多个事件处理程序,可以不用下面这个方法。

function addLoadEvent(func){
 var oldLoad = window.onload;
 if(typeof oldLoad != 'function'){
 window.onload = func();
 }else{
 window.onload = function(){
  oldLoad();
  func();
 }
 }
}



//设置class为list的高度,因为图片的position为absolute所以.list元素的高度为零
//如果一个元素的父元素高度为0,那么设置这个元素的margin: auto 0; 不起作用
function setListHeight(){
 var list = document.getElementById('list');
 var imgItem = list.getElementsByTagName('img')[0];
 var height = imgItem.offsetHeight;
 var list = document.getElementById('list');
 list.style.height = height + 'px';
}

//设置li的层级,可以使用css设置
function setLiIndex(){
 var list = document.getElementById('list');
 var li = list.getElementsByTagName('li');
 var liLen = li.length;
 for(var i = 0;i<liLen;i++){
 li[i].style.zIndex = liLen-i;
 }
}
var index = 1;//index表示当前显示的页面,index是一个全局变量
var timer;// 定时器标识符,如果要清除定时器需要使用它

//事件的跨浏览器绑定的对象
var untilEvent = {
 addEvent:function(element,type,hander){
 if(element.addEventListener){
  element.addEventListener(type,hander,false);
 }else if(element.attachEvent){
  element.attachEvent('on'+type,hander);
 }else{
  element['on'+type] = hander;
 }
 },
 getEvent:function(event){
 return event?event:window.event;
 },
 getTarget:function(event){
 return event.target||event.srcElement;
 }

};
function btnClick(){
 var warp = document.getElementById('warp');
 untilEvent.addEvent(warp,'click',function(event){
 var event = untilEvent.getEvent(event);
 var target = untilEvent.getTarget(event);
 switch(target.id){
  case 'pre': if(index == 1){//如果当前显示的图片已经是第一张图片,当点击切换到"上一张"按钮,则将即将显示的图片设置为最后一张图片
   index =3;
  }else{
   --index;
  }
  anmitate();
  break;
  case 'next':if(index == 3){//如果当前显示的图片已经是最后图片,当点击切换到"下一张"按钮,则将即将显示的图片设置为第一张图片
  index = 1;
  }else{
   ++index;
  }
  anmitate();
  break;
 }
 });
}
//减小图片透明度
function decline(cur,inverTime,inverOpacity){
 var opacityed = parseFloat(cur.style.opacity);
 if(opacityed > 0){
 cur.style.opacity = opacityed-inverOpacity;
 setTimeout(function(){
  decline(cur,inverTime,inverOpacity);
 },inverTime);
 }
}
//切换图片的函数
function anmitate(){
 var list = document.getElementById('list');
 var imgs = list.getElementsByTagName('img');
 var imgsLen = imgs.length;
 var whole = 300;//切换一张图片用的时间
 var inverTime = 5;//时间间隔
 var inverOpacity = 1/(whole/inverTime);
 for(var i = 0;i<imgsLen;i++){
 decline(imgs[i],inverTime,inverOpacity);
 }
 var go = function(){
 var opacityed = parseFloat(imgs[index - 1].style.opacity);
 if(opacityed < 1){
  imgs[index-1].style.opacity = opacityed + inverOpacity;
  setTimeout(go,inverTime);
 }
 };
 go();
}
//打开页面自动切换函数
function play() {
 timer = setTimeout(function () {
 if(index == 3){
  index = 1;
 }else{
  ++index;
 }
 anmitate();
  play();
  //
 }, 3000);
}
//停止切换函数,当鼠标移动到轮播上后取消自动切换,当鼠标从轮播上移开,又开始自动切换
function stop() {
 clearTimeout(timer);
}

//给最外层div添加鼠标移除和鼠标移入地事件处理程序
function getWarp(){
 var warp = document.getElementById('warp');
 untilEvent.addEvent(warp,"mouseout",play);
 untilEvent.addEvent(warp,"mouseover",stop);
}
//函数节流,当改变窗口大小时,图片的大小会变化,所以为了让控制按钮位于轮播垂直方向的中间,li的高度该随图片的大小做变化
function scrollEvent(){
 untilEvent.addEvent(window,"resize",function(){
 throttle(setListHeight);
 });
}
function throttle(method,context){
 clearTimeout(method.Tid);
 method.Tid = setTimeout(method,70);
}
addLoadEvent(scrollEvent);
addLoadEvent(setListHeight);
addLoadEvent(setLiIndex);
addLoadEvent(btnClick);
addLoadEvent(play);
addLoadEvent(getWarp);

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
当json键为数字时的取值方法解析
Nov 15 Javascript
JavaScript动态改变div属性的实现方法
Jul 22 Javascript
14款经典网页图片和文字特效的jQuery插件-前端开发必备
Aug 25 Javascript
特殊日期提示功能的实现方法
Jun 16 Javascript
Vue Transition实现类原生组件跳转过渡动画的示例
Aug 19 Javascript
Ionic学习日记实现验证码倒计时
Feb 08 Javascript
详解如何创建并发布一个 vue 组件
Nov 08 Javascript
详解微信小程序支付流程与梳理
Jul 16 Javascript
Vue 实现从文件中获取文本信息的方法详解
Oct 16 Javascript
Node中对非阻塞I/O、事件循环的知识点总结
Jan 05 Javascript
基于js实现的图片拖拽排序源码实例
Nov 04 Javascript
微信小程序基于ColorUI构建皮皮虾短视频去水印组件
Nov 04 Javascript
深入理解vue路由的使用
Mar 24 #Javascript
原生JS实现导航下拉菜单效果
Nov 25 #Javascript
jQuery插件FusionCharts实现的MSBar2D图效果示例【附demo源码】
Mar 24 #jQuery
基于HTML5+JS实现本地图片裁剪并上传功能
Mar 24 #Javascript
详解Vue-基本标签和自定义控件
Mar 24 #Javascript
JS验证input输入框(字母,数字,符号,中文)
Mar 23 #Javascript
jQuery编写textarea输入字数限制代码
Mar 23 #jQuery
You might like
smarty的保留变量问题
2008/10/23 PHP
php获取文章上一页与下一页的方法
2014/12/01 PHP
CodeIgniter针对数据库的连接、配置及使用方法
2016/03/03 PHP
老生常谈文本文件和二进制文件的区别
2017/02/27 PHP
TP5框架实现上传多张图片的方法分析
2020/03/29 PHP
JavaScript 学习笔记一些小技巧
2010/03/28 Javascript
web页面数据展示新想法(json)
2010/06/08 Javascript
js 立即调用的函数表达式如何写
2014/01/12 Javascript
jquery让返回的内容显示在特定div里(代码少而精悍)
2014/06/23 Javascript
javascript实现base64 md5 sha1 密码加密
2015/09/09 Javascript
jQuery+json实现的简易Ajax调用实例
2015/12/14 Javascript
微信公众号 客服接口的开发实例详解
2016/09/28 Javascript
Javascript vue.js表格分页,ajax异步加载数据
2016/10/24 Javascript
微信小程序通过api接口将json数据展现到小程序示例
2017/01/20 Javascript
Vue 仿百度搜索功能实现代码
2017/02/16 Javascript
nodejs中模块定义实例详解
2017/03/18 NodeJs
Axios学习笔记之使用方法教程
2017/07/21 Javascript
深入解析nodejs HTTP服务
2017/07/25 NodeJs
从零开始实现Vue简单的Toast插件
2018/12/03 Javascript
JavaScript多种滤镜算法实现代码实例
2019/12/10 Javascript
ant design中upload组件上传大文件,显示进度条进度的实例
2020/10/29 Javascript
vue表单验证之禁止input输入框输入空格
2020/12/03 Vue.js
python批量添加zabbix Screens的两个脚本分享
2017/01/16 Python
Python global全局变量函数详解
2018/09/18 Python
python实现微信定时每天和女友发送消息
2019/04/29 Python
Flask框架学习笔记之模板操作实例详解
2019/08/15 Python
python实现飞行棋游戏
2020/02/05 Python
Python多线程Threading、子线程与守护线程实例详解
2020/03/24 Python
python requests包的request()函数中的参数-params和data的区别介绍
2020/05/05 Python
快速解决pymongo操作mongodb的时区问题
2020/12/05 Python
新西兰演唱会和体育门票网站:Ticketmaster新西兰
2017/10/07 全球购物
群众路线个人自我剖析材料
2014/10/07 职场文书
民主评议党员个人总结
2015/02/13 职场文书
老公婚前保证书
2015/02/28 职场文书
使用CSS设置滚动条样式
2022/01/18 HTML / CSS
SQL语句多表联合查询的方法示例
2022/04/18 MySQL