DDjs步步为营:JavaScript查看大图效果[DDbox]

本文详细介绍了一个简易lightbox效果的实现过程,包括设计思路、所需工具、代码实现及整理打包。利用CSS和JavaScript,从零开始创建一个点击图片后背景变暗、图片放大显示的交互效果。

 

 

时常看到一种js效果,点击网页上一个图片,背景变灰,前景出现一个图片框,框里显示被点击图片的大图。著名的实现有lightbox和thickbox。

 

以前看到这种效果觉得很酷,现在自己也来简单实现一个(就叫DDbox哈哈)。

 

第一步:设计

 

页面标记

 

首先要考虑的是在页面文档中要怎么标记这样一个位置:当你点击该位置的时候会出现上文所述效果。

 

考虑到当JavaScript被禁用时,仍能确保一定的用户体验,我们使用带有href属性的a标签。当JavaScript被允许的时候,点击该标签可以展示我们的动画,并且阻止跳转。当JavaScript被禁用的时候,我们通过<a>标签的链接地址转到图片所在位置。

 

这里我们会考虑到图片可能需要一些注释。注释的获取考虑借用属性rel(之前考虑过用自定义的属性字段,但是发现除了IE之外其他浏览器都读不出这些自定义的属性字段),我们把注释相关语句的字符串在页面中写入到rel属性中去。

 

是了,不要忘了,我们还要标记怎样的一个<a>标签才是我们要实现效果的一个位置,加上class属性 class="DDbox"。

 

图片效果

 

接下来设计一下这样的<a>标签被点击时,想要达到的效果。

 

设计大致流程如下:点击class为DDbox的<a>标签

- > 出现灰色覆盖层

- > 图片框在页面中间位置以适宜的大小纵向展开,接着图片渐现(这里暂不考虑图片载入时未能显示的问题)

- > 图片框最终展开,图片框上部是图片,下部是图片注释

- > 鼠标点击覆盖层

- > 图片框与覆盖层同时渐隐消失

 

页面元素

 

根据上面的需求设计页面元素如下,这个比较简单,就不多说了。

 

ContractedBlock.gifExpandedBlockStart.gifCode
<div id="DDoverlay"></div>
<div id="DDimgBox">
    
<div class="imgFrame"><img src="" alt="" /></div>
    
<div class="imgNote"></div>
</div>

 

CSS

 

样式表简单设计如下:

 

ContractedBlock.gifExpandedBlockStart.gifCode
#DDoverlay {
    display
: none ;
    position 
: fixed ; top : 0px ; left : 0px ;
    height 
: 100% ; width : 100% ;
    background-color 
: #000 ; z-index : 1000 ; 
    filter 
: alpha(opacity=60) ; opacity : 0.6 ;
}
#DDimgBox 
{
    display 
: none ;
    position 
: absolute ; 
    border 
: 3px solid #000 ;
    background-color 
: #EEE ;
    padding 
: 8px ; z-index : 1100 ;
    overflow 
: hidden ;
    
/*以下样式实际应用时应省略,这里为演示用*/
    width 
: 602px ;
}
#DDimgBox .imgFrame 
{
    display 
: block ;
    border 
: 1px solid #333 ;
    background-color
: #DDD ;
    
/*以下样式实际应用时应省略,这里为演示用*/
    width 
: 600px ;
}
#DDimgBox .imgNote 
{
    display 
: block ; padding : 8px ;
    text-align 
: center ; color : #333 ;
    font-size
:12px; height : auto ;
}

 

 

使用IE6.0的朋友请注意,这里演示效果的js代码没有考虑IE6.0的兼容性,IE6.0中覆盖层将滑到页面最底部,关闭图片框请到页面底部点击灰色覆盖层。

有时间我再改好,不好意思……

 

第二步:准备工具

 

根据第一步设计的页面标记与图片效果,我们需要准备一些工具,实现以下功能:

 

1. 在文档中获取class属性为"DDbox"标签为<a>的元素,我们可以调用之前介绍过的一个函数hasClass;

2. 阻止默认事件(本例中为页面跳转)的函数,这一个在之前也介绍过stopDefault函数;

3. 元素渐现函数和渐隐函数,我们将其取名为fade,待会会尝试去实现;

4. 考虑到浏览器兼容问题,我们需要封装一个setOpacity函数来设置元素的透明度,用于实现渐隐渐现;

5. 元素展开函数,这个用之前发布过的natrualSlide可以实现,不过这里我们还是重新写一个比较简单的slide函数;

6. 当然不要忘了很重要的一点,如何去实现图片框的适宜大小以及居中定位,这里可能会比较复杂。我们要设计一个函数,通过传入元素长和宽来定位居中位置。

 

暂时想到这些,接下来一个一个实现

 

hasClass函数

ContractedBlock.gifExpandedBlockStart.gifCode
//找出所有具有相同类名的元素
function hasClass(name, type) {
    
var r = [];
    
var re = new RegExp("(^|\\s)" + name + "(\\s|$)");
    
var e = document.getElementsByTagName(type || "*");
    
for (var j = 0; j < e.length; j++)
        
if (re.test(e[j].className))
            r.push(e[j]);
    
return r;
};

 

这里考虑到一个class属性中可能写入多个class style,所以用正则表达式进行检测而不是直接判断相等。

 

stopDefault函数

ContractedBlock.gifExpandedBlockStart.gifCode
// 阻止默认事件
function stopDefault(e) {
    
if (e && e.preventDefault)
        e.preventDefault();
    
else 
        window.event.returnValue 
= false;
    
return false;
}

 

由于ie和其他浏览器的兼容问题,这里必须使用两种方式来阻止默认事件。

  

setOpacity函数

ContractedBlock.gifExpandedBlockStart.gifCode
// 设置元素透明度
function setOpacity(elem, level) {
    
if (elem.filters) 
        elem.style.filter 
= 'alpha(opacity=' + level + ')';
    
else
        elem.style.opacity 
= level / 100;
}

 

第一个分支是处理ie的元素透明度设置,第二个分支是处理其他浏览器的元素透明度设置。

 

这里顺便提醒一下,在ie中要使alpha滤镜起作用,必须搭配position:absolute样式设置,否则透明设置可能不起作用。

 

fade函数

ContractedBlock.gifExpandedBlockStart.gifCode
// 实现渐隐或者渐显动画的函数
//
 参数:动画元素,开始透明度,结束透明度,动画持续时间
//
 返回:动画句柄数组
function fade(elem, startVal, finishVal, time) {
    
var diff = finishVal - startVal;
    
var t = time || 1000;
    
var handles = [];
    
for (var i = 0; i < 100; i++) {
        (
function(n) {
            handles.push( setTimeout(
function() {
                setOpacity(elem, (startVal 
+ diff * n / 100));
            }, t 
* n /100));
        })(i);
    }
    
return handles;
}

 

slide函数

ContractedBlock.gifExpandedBlockStart.gifCode
// 实现滑动动画的函数,可以实现横/纵向滑动展开/收拢,或者横/纵向滑动位移
//
 参数:动画元素,动画属性,开始值,结束值,动画持续时间
//
 动画属性可选值:'top', 'left', 'height', 'left', 'padding', 'margin'
//
 返回:动画句柄数组
function slide(elem, styleName, startVal, finishVal, time) {
    
var diff = finishVal - startVal;
    
var t = time || 1000;
    
var handles = [];
    
for (var i = 0; i < 200; i++) {
        (
function(n) {
            handles.push( setTimeout(
function() {
                elem.style[styleName] 
= (startVal + (diff * n / 200)) + 'px';
            }, t 
* n / 200));
        })(i);
    }
    
return handles;
}

 

一系列获取当前页面或窗口相关长宽和位置的并具有兼容性的函数

ContractedBlock.gifExpandedBlockStart.gifCode
// 获取页面宽度
function pageWidth() {
    
return document.body.scrollWidth;
}

// 获取页面高度
function pageHeight() {
    
return document.body.scrollHeight;
}

// 获取浏览器视口高度
function windowHeight() {
    
var de = document.documentElement;
    
return self.innerHeight || (de && de.clientHeight) || document.body.clientHeight;
}

// 获取浏览器视口宽度
function windowWidth() {
    
var de = document.documentElement;
    
return self.innerWidth || (de && de.clientWidth) || document.body.clientWidth;
}

// 获取当前向右卷动的长度
function scrollX() {
    
var de = document.documentElement;
    
return self.pageXOffset || (de && de.scrollLeft) || document.body.scrollLeft;
}

// 获取当前像下卷动的长度
function scrollY() {
    
var de = document.documentElement;
    
return self.pageYOffset || (de && de.scrollTop) || document.body.scrollTop;
}

 

getCenterPos函数:通过传入长宽值获取中心位置的left和top值

ContractedBlock.gifExpandedBlockStart.gifCode
function getCenterPos(w, h) {
    
return new Array((scrollX() + (windowWidth() - w) / 2), (scrollY() + (windowHeight() - h) / 2));
}

  

第三步:代码实现

 

工具都准备得差不多了,开始进入主体编码阶段,首先要创建我们需要的html结构(前文提到的页面元素),并将其添加到body元素的末尾。

 

createBox函数

 

ContractedBlock.gifExpandedBlockStart.gifCode
function createBox() {
    
// 创建覆盖层DDoverlay
    ol = document.createElement('div');
    ol.id 
= 'DDoverlay';
    
    
// 创建图片框DDimgBox
    pb = document.createElement('div');
    pb.id 
= 'DDimgBox';
    pb.innerHTML 
= '<div class="imgFrame"><img src="" alt="" /></div><div class="imgNote"></div>';
    
    
// 在body元素内部末尾绑定覆盖层和图片框
    document.body.appendChild(ol);
    document.body.appendChild(pb);
}

 

 

接着获取所有的class为DDbox的<a>标签绑定onclick响应函数。

ContractedBlock.gifExpandedBlockStart.gifCode
    var ol = document.getElementById('DDoverlay');
    
var box = document.getElementById('DDimgBox');
    
var im = pb.getElementsByTagName('img')[0];
    
var note = pb.getElementsByTagName('div')[1];
    
var mg = 50;
    
    
var elems = hasClass('DDbox''a');
    
for (var i = 0; i < elems.length; i++) {
        elems[i].onclick 
= showDDbox;
    }

 

其中指定标签click事件的响应函数showDDbox如下:

ContractedBlock.gifExpandedBlockStart.gifCode
    function showDDbox(e) {
        which 
= this;   //习惯性做法,这样可以避免this在函数闭包里面的误用
        
        
// 初始化box里面的一系列元素
         box.style.width = 'auto';
        box.style.height 
= 'auto';
        note.innerHTML 
= which.rel;
        im.style.height 
= 'auto';
        im.style.height 
= 'auto';
        im.src 
= which.href;
        im.alt 
= which.rel;
        setOpacity(im, 
0);
        
        im.onerror 
= function() {
            alert(
'图片载入失败!');
        }
        
        im.onload 
= function() {
            ol.style.display 
= 'block';
            box.style.visibility 
= 'hidden';
            box.style.display 
= 'block';
            
            
//自适应调整图片长宽
            var boxX = box.clientWidth + mg * 2;
            
if ( boxX > windowWidth()) {
                im.style.width 
= (windowWidth() - 20 - mg * 2+ 'px';
                im.style.height 
= 'auto';
            }
            
var boxY = box.clientHeight + mg * 2;
            
if( boxY > windowHeight()) {
                im.style.height 
= (windowHeight() - 60 - mg * 2+ 'px';
                im.style.width 
= 'auto';
            }
            
            
//获取并设置居中位置
            var pos = getCenterPos(box.clientWidth, box.clientHeight);
            box.style.left 
= pos[0+ 'px';
            box.style.top 
= pos[1+ 'px';
            
            
// 图片框展开
            var boxHeight = box.clientHeight-15;
            box.style.height 
= '0px';
            box.style.visibility 
= 'visible';
            slide(box, 
'height'0, boxHeight, 1000);
            
// 图片框展开后图片渐现
            setTimeout(function() {
                fade(im, 
010001000);
            }, 
1001);
        };
        
// 阻止默认事件响应函数,即页面跳转
        return false;
    }

 

可能有些冗长呵呵,没有仔细推敲。

 

另外还要为覆盖层的单击事件绑定一个关闭图片框的函数,这里就简单隐藏掉图片框和覆盖层,不加什么动画效果了。

ContractedBlock.gifExpandedBlockStart.gifCode
    ol.onclick = function() {
        box.style.display 
= 'none';
        ol.style.display 
= 'none';
    }

 

第四步:整理打包

 

DDbox.css

 

#DDoverlay {
    display
: none ;
    position 
: fixed ; top : 0px ; left : 0px ;
    height 
: 100% ; width : 100% ;
    background-color 
: #000 ; z-index : 2000 ; 
    filter 
: alpha(opacity=60) ; opacity : 0.6 ;
}
#DDimgBox 
{
    display 
: none ;
    position 
: absolute ; 
    border 
: 3px solid #000 ;
    background-color 
: #EEE ;
    padding 
: 8px ; z-index : 2100 ;
    overflow 
: hidden ; font-size:12px;
}
#DDimgBox .imgFrame 
{
    display 
: block ;
    border 
: 1px solid #333 ;
    background-color
: #DDD ;
}
#DDimgBox .imgNote 
{
    display 
: block ; padding : 10px ;
    text-align 
: center ; color : #333 ;
    height 
: auto ;
}

 

DDutil.js

 

ContractedBlock.gifExpandedBlockStart.gifCode

//获取居中位置
function getCenterPos(w, h) {
    
return new Array((scrollX() + (windowWidth() - w) / 2), (scrollY() + (windowHeight() - h) / 2));
}

//找出所有具有相同类名的元素
function hasClass(name, type) {
    
var r = [];
    
var re = new RegExp("(^|\\s)" + name + "(\\s|$)");
    
var e = document.getElementsByTagName(type || "*");
    
for (var j = 0; j < e.length; j++)
        
if (re.test(e[j].className))
            r.push(e[j]);
    
return r;
};

function stopBubble(e) {
    
// 如果传入了事件对象,那么就是非IE浏览器
    if (e && e.stopPropagation)
        
// 支持W3C的stopPropation()方法
        e.stopPropagation();
    
else
        
// 否则,我们得使用IE的方式来取消事件冒泡
        window.event.cancelBubble = true;
}

function stopDefault(e) {
    
if (e && e.preventDefault)
        e.preventDefault();
    
else 
        window.event.returnValue 
= false;
    
return false;
}

function setOpacity(elem, level) {
    
//注意这里两个filter的单复数形式
    if (elem.filters) 
        elem.style.filter 
= 'alpha(opacity=' + level + ')';
    
else
        elem.style.opacity 
= level / 100;
}

function fade(elem, startVal, finishVal, time) {
    
var diff = finishVal - startVal;
    
var t = time || 1000;
    
var handles = [];
    
for (var i = 0; i < 100; i++) {
        (
function(n) {
            handles.push( setTimeout(
function() {
                setOpacity(elem, (startVal 
+ diff * n / 100));
            }, t 
* n /100));
        })(i);
    }
    
return handles;
}

function slide(elem, styleName, startVal, finishVal, time) {
    
var diff = finishVal - startVal;
    
var t = time || 1000;
    
var handles = [];
    
for (var i = 0; i < 200; i++) {
        (
function(n) {
            handles.push( setTimeout(
function() {
                elem.style[styleName] 
= (startVal + (diff * n / 200)) + 'px';
            }, t 
* n / 200));
        })(i);
    }
    
return handles;
}

// 获取页面宽度
function pageWidth() {
    
return document.body.scrollWidth;
}

// 获取页面高度
function pageHeight() {
    
return document.body.scrollHeight;
}

// 获取浏览器视口高度
function windowHeight() {
    
var de = document.documentElement;
    
return self.innerHeight || (de && de.clientHeight) || document.body.clientHeight;
}

// 获取浏览器视口宽度
function windowWidth() {
    
var de = document.documentElement;
    
return self.innerWidth || (de && de.clientWidth) || document.body.clientWidth;
}

// 获取当前向右卷动的长度
function scrollX() {
    
var de = document.documentElement;
    
return self.pageXOffset || (de && de.scrollLeft) || document.body.scrollLeft;
}

// 获取当前像下卷动的长度
function scrollY() {
    
var de = document.documentElement;
    
return self.pageYOffset || (de && de.scrollTop) || document.body.scrollTop;
}


// addEvent/removeEvent written by Dean Edwards, 2005
//
 with input from Tino Zijdel
//
 http://dean.edwards.name/weblog/2005/10/add-event/

function addEvent(element, type, handler) {
    
// assign each event handler a unique ID
    if (!handler.$$guid) handler.$$guid = addEvent.guid++;
    
// create a hash table of event types for the element
    if (!element.events) element.events = {};
    
// create a hash table of event handlers for each element/event pair
    var handlers = element.events[type];
    
if (!handlers) {
        handlers 
= element.events[type] = {};
        
// store the existing event handler (if there is one)
        if (element["on" + type]) {
            handlers[
0= element["on" + type];
        }
    }
    
// store the event handler in the hash table
    handlers[handler.$$guid] = handler;
    
// assign a global event handler to do all the work
    element["on" + type] = handleEvent;
};
// a counter used to create unique IDs
addEvent.guid = 1;

function removeEvent(element, type, handler) {
    
// delete the event handler from the hash table
    if (element.events && element.events[type]) {
        
delete element.events[type][handler.$$guid];
    }
};

function handleEvent(event) {
    
var returnValue = true;
    
// grab the event object (IE uses a global event object)
    event = event || fixEvent(window.event);
    
// get a reference to the hash table of event handlers
    var handlers = this.events[event.type];
    
// execute each event handler
    for (var i in handlers) {
        
this.$$handleEvent = handlers[i];
        
if (this.$$handleEvent(event) === false) {
            returnValue 
= false;
        }
    }
    
return returnValue;
};

function fixEvent(event) {
    
// add W3C standard event methods
    event.preventDefault = fixEvent.preventDefault;
    event.stopPropagation 
= fixEvent.stopPropagation;
    
return event;
};
fixEvent.preventDefault 
= function() {
    
this.returnValue = false;
};
fixEvent.stopPropagation 
= function() {
    
this.cancelBubble = true;
};

function domReady( f ) {
    
// If the DOM is already loaded, execute the function right away
    if ( domReady.done ) return f();

    
// If we’ve already added a function
    if ( domReady.timer ) {
        
// Add it to the list of functions to execute
        domReady.ready.push( f  );
    } 
else {
        
// Attach an event for when the page finishes  loading,
        // just in case it finishes first. Uses addEvent.
        addEvent( window, "load", isDOMReady );

        
// Initialize the array of functions to execute
        domReady.ready = [ f ];

        
//  Check to see if the DOM is ready as quickly as possible
        domReady.timer = setInterval( isDOMReady, 13 );
    }
}

// Checks to see if the DOM is ready for navigation
function isDOMReady() {
    
// If we already figured out that the page is ready, ignore
    if ( domReady.done ) return false;

    
// Check to see if a number of functions and elements are
    // able to be accessed
    if ( document && document.getElementsByTagName && 
          document.getElementById 
&& document.body ) {

        
// If they’re ready, we can stop checking
        clearInterval( domReady.timer );
        domReady.timer 
= null;

        
// Execute all the functions that were waiting
        for ( var i = 0; i < domReady.ready.length; i++ )
            domReady.ready[i]();

        
// Remember that we’re now done
        domReady.ready = null;
        domReady.done 
= true;
    }
}

 

DDbox.js

 

addEvent(window, 'load', runDDbox);

function runDDbox() {
    createBox();
    
var ol = document.getElementById('DDoverlay');
    
var box = document.getElementById('DDimgBox');
    
var im = pb.getElementsByTagName('img')[0];
    
var note = pb.getElementsByTagName('div')[1];
    
var mg = 50;
    
    
var elems = hasClass('DDbox''a');
    
for (var i = 0; i < elems.length; i++) {
        elems[i].onclick 
= showDDbox;
    }
    
    
function showDDbox(e) {
        which 
= this;   //习惯性做法,这样可以避免this在函数闭包里面的误用
        
        
// 初始化box里面的一系列元素
        box.style.width = 'auto';
        box.style.height 
= 'auto';
        note.innerHTML 
= which.rel;
        im.style.height 
= 'auto';
        im.style.height 
= 'auto';
        im.src 
= which.href;
        im.alt 
= which.rel;
        setOpacity(im, 
0);
        
        im.onerror 
= function() {
            alert(
'图片载入失败!');
        }
        
        im.onload 
= function() {
            ol.style.display 
= 'block';
            box.style.visibility 
= 'hidden';
            setOpacity(box, 
100);
            box.style.display 
= 'block';
            
            
//自适应调整图片长宽
            var boxX = box.clientWidth + mg * 2;
            
if ( boxX > windowWidth()) {
                im.style.width 
= (windowWidth() - 20 - mg * 2+ 'px';
                im.style.height 
= 'auto';
            }
            
var boxY = box.clientHeight + mg * 2;
            
if( boxY > windowHeight()) {
                im.style.height 
= (windowHeight() - 60 - mg * 2+ 'px';
                im.style.width 
= 'auto';
            }
            
            
//获取并设置居中位置
            var pos = getCenterPos(box.clientWidth, box.clientHeight);
            box.style.left 
= pos[0+ 'px';
            box.style.top 
= pos[1+ 'px';
            
            
// 图片框展开同时渐显
            var boxHeight = box.clientHeight-15;
            box.style.height 
= '0px';
            box.style.visibility 
= 'visible';
            slide(box, 
'height'0, boxHeight, 800);
            fade(im, 
0100900);
        };
        
// 阻止默认事件响应函数,即页面跳转
        return false;
    }
    
    ol.onclick 
= function() {
        
//图片框向上浮动同时渐隐
        slide(box, 'top', parseInt(box.style.top), scrollY(), 300);
        fade(box, 
1000250);
        ol.style.display 
= 'none';
        setTimeout(
function() {
            box.style.display 
= 'none';
        }, 
250);
    }
    
    
function createBox() {
        
// 创建覆盖层DDoverlay
        ol = document.createElement('div');
        ol.id 
= 'DDoverlay';
        
        
// 创建图片框DDimgBox
        pb = document.createElement('div');
        pb.id 
= 'DDimgBox';
        pb.innerHTML 
= '<div class="imgFrame"><img src="" alt="" /></div><div class="imgNote"></div>';
        
        
// 在body元素内部末尾绑定覆盖层和图片框
        document.body.appendChild(ol);
        document.body.appendChild(pb);
    }
    
}

 

 

 

转载于:https://www.cnblogs.com/zhengchuyu/archive/2008/08/05/1261141.html

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值