瀑布流特效,回到顶部特效,放大镜特效,选项卡原理分析

来源:互联网 发布:暮色谷的新域名问题 编辑:程序博客网 时间:2024/06/15 08:06

特效1:放大镜特效

<div id="demo">    <div id="small-box">        <div id="mark" style="background-color:red;"></div>        <div id="float-box"></div>        <img src="macbook-small.jpg"/>    </div>    <div id="big-box">        <img src="macbook-big.jpg"/>    </div></div>
其中demo是相对布局
 /*这是大盒子,用于存放所有元素,同时是相对定位*/        #demo {            display: block;            width: 400px;            height: 255px;            margin: 50px;            position: relative;            border: 1px solid #ccc;        }
big-box也就是存放大图片的容器是绝对定位,于是他是相对于demo来定位的,同时用left/top使得自己脱离了文档流了,于是父元素的css对其失效,如background

  /*相对于demo定位,但是demo只有400px,而这里是460,那么就会超过demo右边60px   同时设置了超出隐藏,因为这里用float脱离了文档流,所以父元素已经对它没有限制了,也就是限制无效了!   */        #big-box {              position: absolute;            top: 0;            left: 460px;            width: 400px;            height: 300px;            overflow: hidden;            border: 1px solid red;            z-index: 1;;        }        #big-box img {            position: absolute;            z-index: 5        }
big-box实际上用来显示的是图片的局部区域,图片的真实宽度用offsetHeight等设置,只不过这里是设置了超出影藏了,img的z-index高于大图片容器!
小图片容器使用了relative定位,也就是相对于自己应该在文档中出现的位置来定位的

 /*相对自己定位*/        #small-box {            position: relative;            z-index: 1;        }
mark是一个遮罩层,其height/width都是和小图片容器一致的,那么就会完全覆盖小图片的容器,而是是absolute定位的:

 /*mark是宽度和demo一样,同时是absolute布局,所以他会覆盖掉demo的所有的区域,所以他的作用就是作为一个遮罩层用于处理事件*/        #mark {            position: absolute;            display: block;            width: 400px;            height: 255px;            background-color: red;            filter: alpha(opacity=0);            opacity: 0;            z-index: 10;        }
float-box是真正的放大镜,他是absolute定位的,所以他会浮动在遮罩层的上面,因为他的z-index明显要高:

 /*这才是真正的放大镜,他是采用absolute定位,所以相对于自己的父元素定位,因此又定位在左上角了!  同时透明度是0.5表示半透明!*/        #float-box {            display: none;            width: 160px;            height: 120px;            position: absolute;            background: #ffffcc;            border: 1px solid #ccc;            filter: alpha(opacity=50);            opacity: 0.5;        }
放大镜特效的原理:小图片宽度B/大图片宽度D=放大镜宽度A/大图片局部宽度C=放大镜移动距离x/大图片移动距离y。通过该图,我们的目地就是通过鼠标移动的距离获取到大图片移动的距离!那么我们如何通过鼠标移动的距离获取到大图片区域移动的位移呢:

                 var left = _event.clientX - objDemo.offsetLeft - objSmallBox.offsetLeft - objFloatBox.offsetWidth / 2;                var top = _event.clientY - objDemo.offsetTop - objSmallBox.offsetTop - objFloatBox.offsetHeight / 2;//其实还要减去父元素的border值
通过鼠标位移获取到放大镜应该的移动的距离以后,把这个距离设置给放大镜:

      if (left < 0) {                    left = 0;                } else if (left > (objMark.offsetWidth - objFloatBox.offsetWidth)) {                    left = objMark.offsetWidth - objFloatBox.offsetWidth;                }                if (top < 0) {                    top = 0;                } else if (top > (objMark.offsetHeight - objFloatBox.offsetHeight)) {                    top = objMark.offsetHeight - objFloatBox.offsetHeight;                }                //设置放大镜相对于父元素左边的距离!                objFloatBox.style.left = left + "px";                objFloatBox.style.top = top + "px";
根据公式:小图片宽度B/大图片宽度D=放大镜宽度A/大图片局部宽度C=放大镜移动距离x/大图片移动距离y这个恒等式可以得到:(B-A)/(D-C)=x/y,其中x表示放大镜移动的距离,所以y=(D-C)x/(B-A):

                var percentX = left / (objMark.offsetWidth - objFloatBox.offsetWidth);//获取到x/(B-A)                var percentY = top / (objMark.offsetHeight - objFloatBox.offsetHeight);                objBigBoxImage.style.left = -percentX * (objBigBoxImage.offsetWidth - objBigBox.offsetWidth) + "px";                objBigBoxImage.style.top = -percentY * (objBigBoxImage.offsetHeight - objBigBox.offsetHeight) + "px";
大图片宽度通过获取到图片本身的offsetWidth(它只不过设置了超出隐藏了),大图片局部的宽度就是大图片容器的宽度,同时方向移动是相反的!

特效2:微信二维码切换特效(纯CSS实现)

   <div  class="elevator"><a class="elevator-weixin"><div class="elevator-weixin-box"></div></a>   </div>
实现的效果就是当鼠标放置到超链接上面以后,那么二维码就会弹出来,当然也可以设置特效:

elevator使用了绝对定位:

/*回到顶部,把这个大的div固定在右边,通过fixed脱离文档流,并且在可视区域之内进行定位,同时设置z-index的值足够大!*/.elevator {  position: fixed;  right: 15px;  bottom: 10px;  z-index: 1030;}
a标签的定位属性:

/*下面的a标签全部是block水平的,同时relative进行定位,也就是相对于自己本来的位置来定位!*/.elevator a {  display: block;  position: relative;  height: 52px;  width: 52px;   /*这里是通过transition来过渡元素的background-position的,实现连续效果!  -webkit-transition: background-position 0.15s;  -moz-transition: background-position 0.15s;  transition: background-position 0.15s;  */  background: url(images/elevator.png?1) no-repeat;}
定位到cssSprite图片上微信的图标:

/*设置第一个微信的图标*/.elevator .elevator-weixin {  background-position: 0 -860px;}
设置微信图表的hover事件,把opaticy设置为完全不透明,那么就可见了,同时我们设置了背景图片以及背景切换的动画

/*微信鼠标点击的图表*/.elevator .elevator-weixin:hover {  background-position: 0 -922px;}/*设置elevator-weixin鼠标悬停的时候的elevator-weixin-box的样式!*/.elevator .elevator-weixin:hover .elevator-weixin-box {  display: block;  visibility: visible;/*这两个属性可以不设置,因为上面的elevator-weixin-box是通过opacity和max-width来隐藏元素的*/  opacity: 1;  filter: alpha(opacity=100);   max-width: none;/*表示对元素的最大宽度限制不存在,也就说不限制他的宽度!*/  /*  -webkit-transform: scale(1);  -ms-transform: scale(1);  transform: scale(1);  */}
默认的时候是完全透明的,也就是当没有把鼠标移动到上面的时候是看不见elevator-weixin-box的:

/*对微信盒子的处理,  position: absolute;表示这个盒子脱离文档流,但是还是在原来的位置上  但是用到了bottom/right来定位自己,设置right为46px表示相对于右边的距离是46px,这就是相对于外面的a标签46px  而bottom表示相对于自己的底部定位,-10px表示*/.elevator .elevator-weixin-box {  position: absolute;  width: 172px;  height: 212px;  /*这里的bottom/right可能需要精确的调整,因为后面的a标签虽然设置了高度和宽度,但是有可能在这个宽度里面有一部分空白,所以要调节他*/  bottom: -10px;  right: 46px; /*  -webkit-transition: opacity 0.25s, transform .3s;  -moz-transition: opacity 0.25s, transform .3s;  transition: opacity 0.25s, transform .3s;  */  opacity: 0;  filter: alpha(opacity=0);  max-width: 0;  /*  -webkit-transform: scale(0.01);  -ms-transform: scale(0.01);  transform: scale(0.01);  -webkit-transform-origin: 100% 95%;  -ms-transform-origin: 100% 95%;  transform-origin: 100% 95%;  */  background: url(images/elevator.png) no-repeat 0 0;}
特效3:回到顶部特效
     <div class="box">   <img src="images/tb_bg.jpg"></img></div>    <a href="javascript:;" id="btn" title="回到顶部"></a>
首先对按钮进行定位:

              #btn{  width:40px;  height:40px;/*正常情况下显示上面一部分*/  position:fixed;   left:50%; /*加上网页中间部分一半*/              margin-left:610px;   bottom:30px;   background:url(images/top_bg.png) no-repeat left top;   display:block; }
按钮的hover事件用来切换背景图片

        #btn:hover{ background:url(images/top_bg.png) no-repeat left -40px;}

原理在于:

var top=document.documentElement.scrollTop||document.body.scrollTop;           if(top>=clientHeight)   {     button.style.display="block";   }else//回到第一屏隐藏   {    button.style.display="none";   }
如果滚动条滚动的距离大于窗口可视区域的高度,这时候元素显示出来,否则隐藏元素!

为按钮注册点击事件:

   /*注册按钮的点击事件*/ button.onclick=function() { timer=setInterval(function() {  /*google的浏览器的用body.scrollTop来判断,该属性可读可写!*/   var top=document.documentElement.scrollTop||document.body.scrollTop;//这里如果用正数,那么舍入的时候会往下舍入,导致每次减去的像素较少,所以最后减去不到0,于是不会触发清除定时器的代码//但是,如果是负数,那么舍入的时候会变成更小的负数,导致最后可以减少到0!isTop=true;   var speed=Math.floor(-top/3);   document.documentElement.scrollTop=document.body.scrollTop=top+speed;   /*因为自己不会到达为0的顶部,改成Math.floor(-top/3)也就是变成负数就可以了!*/  if(top==0)  {clearInterval(timer);  } },30);}
如果点击了回到顶部,同时滚动了滚动条,这时候就需要清除定时器:

     window.onscroll=function() {   var top=document.documentElement.scrollTop||document.body.scrollTop;             if(top>=clientHeight)   {     button.style.display="block";   }else//回到第一屏隐藏   {    button.style.display="none";   }   if(!isTop)   { clearInterval(timer);   }   isTop=false;}
这时候点击回到顶部以后,第一次scroll时候isTop变成了false,第二次滚动的时候就会清除定时器了!
特效4:瀑布流布局
<div id="main">    <div class="pin">        <div class="box">            <img src="./images/1.jpg"/>        </div>    </div>    <div class="pin">        <div class="box">            <img src="./images/2.jpg"/>        </div>    </div></div>
如何解决元素层次不齐排列(因为我们使用了浮动布局,从而形成了文字环绕效果)
CSS部分

/*设置为relative,以后pin元素全部相对于它来定位*/    #main{        position: relative;    }/*这里全部用了padding值,因为后面我用了offsetWidth/offsetHeight来获取元素的空间,而offsetWidth等不包含margin,所以用了padding值!*/    .pin{        padding: 15px 0 0 15px;        float:left;    }    .box{        padding: 10px;        border:1px solid #ccc;        box-shadow: 0 0 6px #ccc;        border-radius: 5px;    }    .box img{        width:162px;        height:auto;    }
瀑布流布局原理:下一行元素和上一行最矮的元素对齐,获取他的offsetLeft值赋值给自己;我们获取每一列的高度,然后在高度最小的那一列元素下继续排列下面的元素

获取每一行可以排列的元素的个数,依此来设置父元素的宽度:

    var num=Math.floor(document.documentElement.clientWidth/iPinW);//每行中能容纳的pin个数【窗口宽度除以一个块框宽度】    oParent.style.cssText='width:'+iPinW*num+'px;margin:0 auto;';//设置父级居中样式:定宽+自动水平外边距
设置一个数组用于保存每一列当前的高度,对于第一行的元素就是offsetHeight,以后没添加一个元素该列的高度都需要动态更新:

 var pinHArr=[];//用于存储每列中的所有块框相加的高度。    for(var i=0;i<aPin.length;i++){//遍历数组aPin的每个块框元素        var pinH=aPin[i].offsetHeight;        if(i<num){            pinHArr[i]=pinH; //第一行中的num个块框pin 先添加进数组pinHArr        }else{            var minH=Math.min.apply(null,pinHArr);//数组pinHArr中的最小值minH,以后每次添加一个元素都需要动态更新该列的值!            var minHIndex=getminHIndex(pinHArr,minH);            aPin[i].style.position='absolute';//设置绝对位移,添加两个该元素就需要设置该元素的垂直和水平方向的偏移!            aPin[i].style.top=minH+'px';            aPin[i].style.left=aPin[minHIndex].offsetLeft+'px';            //添加了该元素以后就需要动态更新该列当前的高度!            pinHArr[minHIndex]+=aPin[i].offsetHeight;        }    }
瀑布流具有动态加载元素的特效,那么如何判断元素是否在当前可视区域之内
//如果当前元素距离距离文档的距离已经小于窗口滚动距离和浏览器可视区域之和,那么动态加载!function checkscrollside(){    var oParent=document.getElementById('main');    var aPin=getClassObj(oParent,'pin');    var lastPinH=aPin[aPin.length-1].offsetTop+Math.floor(aPin[aPin.length-1].offsetHeight/2);//创建【触发添加块框函数waterfall()】的高度:最后一个块框的距离网页顶部+自身高的一半(实现未滚到底就开始加载)    var scrollTop=document.documentElement.scrollTop||document.body.scrollTop;//注意解决兼容性    var documentH=document.documentElement.clientHeight;//页面高度    return (lastPinH<scrollTop+documentH)?true:false;//到达指定高度后 返回true,触发waterfall()函数}
动态添加元素到页面尾部:

window.onload=function(){     //为了不让元素加载时候参差不齐,我们按照特定的规则加载    waterfall('main','pin');//动态加载元素,从服务器获取到    var dataInt={'data':[{'src':'1.jpg'},{'src':'2.jpg'},{'src':'3.jpg'},{'src':'4.jpg'}]};    window.onscroll=function(){//如果在可视区域之内,那么动态加载!        if(checkscrollside()){            var oParent = document.getElementById('main');// 父级对象            for(var i=0;i<dataInt.data.length;i++){                var oPin=document.createElement('div'); //添加 元素节点                oPin.className='pin';                   //添加 类名 name属性                oParent.appendChild(oPin);              //添加 子节点                var oBox=document.createElement('div');                oBox.className='box';                oPin.appendChild(oBox);                var oImg=document.createElement('img');                oImg.src='./images/'+dataInt.data[i].src;                oBox.appendChild(oImg);            }//加载完成以手动调用waterfall,解决参差不齐问题,强烈建议这里用文档碎片减少页面重绘!            waterfall('main','pin');        };    }

特效5:选项卡特效

<div id="notice" class="notice"><div id="notice-tit" class="notice-tit">  <ul>  <li>  <a href="#">公告</a>  </li>  <li>  <a href="#">规则</a>  </li>  <li>  <a href="#">论坛</a>  </li>  <li>  <a href="#">安全</a>  </li>  <li class="select">  <a href="#">公益</a>  </li>  </ul></div>  </div>
那么这时候是如何进行布局的呢?

notice是整个选项卡的对象

/*notice宽度为298px+2px=300px的宽度,最外面的盒子*/.notice{width:298px;        height:98px;        margin:10px;        border:1px solid red;    overflow:hidden;       }
notice-tit是标题部分:

   .notice-tit{height:27px;            position:relative;            background:#F7F7F7;}
他采用了相对定位,也就是说后面的ul是相对于他来定位的:

     .notice-tit ul{                    position:absolute;                     width:300px;    left:-1px;    }
那么这个ul里面的li是如何定位的:

.notice-tit li{float:left;               width:58px;               height:26px;               line-height:26px;               text-align:center;               overflow:hidden;               background:#FFF;               padding:0 1px;               background:#F7F7F7;               border-bottom:1px solid #eee;}
从这里我们知道每一个li占据的宽度是60px,那么5个li要成为一排那么至少也要300px,也就是说ul对象的width至少也是300px,这一点非常重要。同时我们看到notice是298px,也就是说只有298px可以用于存放子元素,同时设置了超出隐藏,所以如果我把ul对象设置为300px,那么除了占据他可以用于存放子元素的298px以外,还有2px,他会超出父元素的border同时还会剩余1px(其中1px用于覆盖父元素的border)!但是,我们ul必须要300px啊,那么怎么办?为了防止我的子元素的border和父元素border都出现,从而导致边框是2px,那么我只要把宽度设置为300px的同时把left值设置为-1,那么我就会完全覆盖掉父元素的border!(注意:上面只要大于等于300px都是可以的,因为最外层的父元素设置了超出隐藏了,但是如果小于300px那么就不会在同一行中显示)
当然,如果想到定位,那么肯定可以考虑margin负值,其实这里就可以用margin负值来完成:

         .notice-tit ul{                        position:absolute;   width:300px;   margin-left:-1px; }
通过把上面的ul设置margin负值也是同样的道理,其仍然可以用于覆盖父元素的border!所以"负margin或者负数left"都是可以的!
我们再来看看li元素如果触发了事件时候的css代码:

  .notice-tit li.select{background:#FFF;                      border-bottom-color:#FFF;                      border-left:1px solid red;                      border-right:1px solid red;                      padding:0;                      font-weight:bolder;}
如果当元素触发了事件以后,我们就会添加左右的border,但是同时把padding设置为0,于是ul对象的整体的宽度还是没有变化的,很奇妙的办法,用padding和border替换!
原理:根据鼠标划过的元素决定显示下面那一个选项卡的内容!
自动播放并修改当前所在元素的下标值:

 // 添加定时器,改变当前高亮的索引!  timer=setInterval(autoPlay,2000);  function autoPlay(){  //自动播放的时候索引自动增加!      index++;      if(index>=lis.length){         index=0;      }      changeOption(index);  }//索引增加了,那么我们修改当前应该所处的界面状态!  function changeOption(curIndex){    for(var j=0;j<lis.length;j++){       lis[j].className='';       divs[j].style.display='none';    }    // 高亮显示当前页签    lis[curIndex].className='select';    divs[curIndex].style.display='block';//这里就是为了解决bug了,解决onmouseover也能够修改index值!    index=curIndex;  }}
changeOption表示如果鼠标划过了元素,那么就需要把当前所在的下标设置为划过的元素的下标!
如果鼠标滑动过快,这时候会添加很多定时器准备执行,但是这些定时器都是不应该被执行了,所以在设置定时器之前我们需要手动清除这些没有触发的定时器:

  //如果滑动过快,这时候就会出现很多定时器等待被执行,所以在调用之前必须  //手动清除等待的定时器!  if(timer){    clearInterval(timer);    timer=null;  } 
为每一个li元素都设置onmouseover/onmouseout事件:

  var lis=$('notice-tit').getElementsByTagName('li');  var divs=$('notice-con').getElementsByTagName('div');  // 遍历每一个页签且给他们绑定事件,也就是为他们绑定onmouseover/onmouseout事件  //但是只要onmouseover事件触发了,那么清除定时器,同时改变当前的选项为自身。  //onmouseout触发了,那么回调自动播放!  for(var i=0;i<lis.length;i++){    lis[i].id=i;    lis[i].onmouseover=function(){      clearInterval(timer);  //为了解决这个bug,我们用changeOption这个方法,当onmouseover事件触发的时候  //我们修改index才行!      changeOption(this.id);    }//离开时候继续执行定时器,但这时候可能出现bug,也就是老是从第一个开始,因为index在onmouseover/onmouseout中一直没有变化!    lis[i].onmouseout=function(){        timer=setInterval(autoPlay,2000);        }  }

效果6:弹出层效果

原理:通过在body中动态添加遮罩层和登录页面,并且通过z-index控制登录页面和遮罩层在垂直方向上的位置

问题1:如何确定遮罩层的大小?

/*遮罩层,绝对定位*/#mask{ background-color:#ccc;opacity:0.5;filter: alpha(opacity=50); position:absolute; left:0;top:0;z-index:1000;}
通过css我们知道,我们并没有指定遮罩层的高度和宽度,而是通过js动态获取到遮罩层的尺寸的
 function getDocParameter() {   if(document.compatMode=='BackCompat')//怪异模式   {       return{    docHeight:Math.max(document.body.scrollHeight,document.body.clientHeight),docWidth:Math.max(document.body.scrollWidth,document.body.clientHeight)    }   }else//标准模式   {    return{    docHeight:Math.max(document.documentElement.scrollHeight,document.documentElement.clientHeight),  docWidth:Math.max(document.documentElement.scrollWidth,document.documentElement.clientHeight)    }   } }

上面是为了获取在怪异模式和标准模式下,当没有出现滚动条时候不同浏览器获取文档高度不同的情况。创建遮罩层并且设置为文档总高度:

//获取页面的高度和宽度,如果有滚动条,那么包含滚动距离,如果页面没有滚动条就要兼容不同浏览器var sWidth=getDocParameter().docWidth;var sHeight=getDocParameter().docHeight;var oMask=document.createElement("div");oMask.id="mask";//创建了遮罩层,遮罩层的高度和宽度是页面的总高度和宽度!oMask.style.height=sHeight+"px";oMask.style.width=sWidth+"px";//遮罩层的高度和宽度是页面的总高度和宽度,同时插入到DOM中!document.body.appendChild(oMask);
登录框相对于可视区域定位,在可视区域最中间:

/*固定定位,在页面中间,比遮罩层更高*/#login{ position:fixed;z-index:1001;}/*登录页面信息*/.loginCon{ position:relative; width:670px;height:380px;background:url(img/loginBg.png) #2A2C2E center center no-repeat;}
我们先获取可是区域的高度和宽度:

//获取页面的可视区域高度和宽度var wHeight=document.documentElement.clientHeight||document.body.clientHeight;
我们把登录框进行定位,相对于可视区域:

//创建登录框,同时在登录框里面通过innerHTML设置var oLogin=document.createElement("div");oLogin.id="login";oLogin.innerHTML="<div class='loginCon'><div id='close'>关闭</div></div>";document.body.appendChild(oLogin);//获取登陆框的宽和高,但是必须在元素插入到DOM中以后才能获取到!var dHeight=oLogin.offsetHeight;var dWidth=oLogin.offsetWidth;//设置登陆框的left和topoLogin.style.left=sWidth/2-dWidth/2+"px";oLogin.style.top=wHeight/2-dHeight/2+"px";
登录框距离左边的距离为:(可视区域-登录框的宽度)/2,距离上边的距离为:(可视区域的高度-登录框的高度)/2就可以了!
点击关闭按钮和点击遮罩层其它地方都会关闭遮罩层:

//点击关闭按钮var oClose=document.getElementById("close");//关闭登录框和遮罩层!这样点击遮罩层也能够关闭,这就是不错的效果!oClose.onclick=oMask.onclick=function(){document.body.removeChild(oLogin);document.body.removeChild(oMask);};};


1 0
原创粉丝点击