时常看到一种js效果,点击网页上一个图片,背景变灰,前景出现一个图片框,框里显示被点击图片的大图。著名的实现有lightbox和thickbox。
以前看到这种效果觉得很酷,现在自己也来简单实现一个(就叫DDbox哈哈)。
第一步:设计
页面标记
首先要考虑的是在页面文档中要怎么标记这样一个位置:当你点击该位置的时候会出现上文所述效果。
考虑到当JavaScript被禁用时,仍能确保一定的用户体验,我们使用带有href属性的a标签。当JavaScript被允许的时候,点击该标签可以展示我们的动画,并且阻止跳转。当JavaScript被禁用的时候,我们通过<a>标签的链接地址转到图片所在位置。
这里我们会考虑到图片可能需要一些注释。注释的获取考虑借用属性rel(之前考虑过用自定义的属性字段,但是发现除了IE之外其他浏览器都读不出这些自定义的属性字段),我们把注释相关语句的字符串在页面中写入到rel属性中去。
是了,不要忘了,我们还要标记怎样的一个<a>标签才是我们要实现效果的一个位置,加上class属性 class="DDbox"。
图片效果
接下来设计一下这样的<a>标签被点击时,想要达到的效果。
设计大致流程如下:点击class为DDbox的<a>标签
- > 出现灰色覆盖层
- > 图片框在页面中间位置以适宜的大小纵向展开,接着图片渐现(这里暂不考虑图片载入时未能显示的问题)
- > 图片框最终展开,图片框上部是图片,下部是图片注释
- > 鼠标点击覆盖层
- > 图片框与覆盖层同时渐隐消失
页面元素
根据上面的需求设计页面元素如下,这个比较简单,就不多说了。
<div id="DDoverlay"></div>
<div id="DDimgBox">
<div class="imgFrame"><img src="" alt="" /></div>
<div class="imgNote"></div>
</div>
CSS
样式表简单设计如下:
#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函数
//找出所有具有相同类名的元素
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函数
// 阻止默认事件
function stopDefault(e) {
if (e && e.preventDefault)
e.preventDefault();
else
window.event.returnValue = false;
return false;
}
由于ie和其他浏览器的兼容问题,这里必须使用两种方式来阻止默认事件。
setOpacity函数
// 设置元素透明度
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函数
// 实现渐隐或者渐显动画的函数
// 参数:动画元素,开始透明度,结束透明度,动画持续时间
// 返回:动画句柄数组
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函数
// 实现滑动动画的函数,可以实现横/纵向滑动展开/收拢,或者横/纵向滑动位移
// 参数:动画元素,动画属性,开始值,结束值,动画持续时间
// 动画属性可选值:'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;
}
一系列获取当前页面或窗口相关长宽和位置的并具有兼容性的函数
// 获取页面宽度
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值
function getCenterPos(w, h) {
return new Array((scrollX() + (windowWidth() - w) / 2), (scrollY() + (windowHeight() - h) / 2));
}
第三步:代码实现
工具都准备得差不多了,开始进入主体编码阶段,首先要创建我们需要的html结构(前文提到的页面元素),并将其添加到body元素的末尾。
createBox函数
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响应函数。
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如下:
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, 0, 1000, 1000);
}, 1001);
};
// 阻止默认事件响应函数,即页面跳转
return false;
}
可能有些冗长呵呵,没有仔细推敲。
另外还要为覆盖层的单击事件绑定一个关闭图片框的函数,这里就简单隐藏掉图片框和覆盖层,不加什么动画效果了。
ol.onclick = function() {
box.style.display = 'none';
ol.style.display = 'none';
}
第四步:整理打包
DDbox.css
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
//获取居中位置
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
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, 0, 100, 900);
};
// 阻止默认事件响应函数,即页面跳转
return false;
}
ol.onclick = function() {
//图片框向上浮动同时渐隐
slide(box, 'top', parseInt(box.style.top), scrollY(), 300);
fade(box, 100, 0, 250);
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);
}
}
本文详细介绍了一个简易lightbox效果的实现过程,包括设计思路、所需工具、代码实现及整理打包。利用CSS和JavaScript,从零开始创建一个点击图片后背景变暗、图片放大显示的交互效果。
1936

被折叠的 条评论
为什么被折叠?



