在前面的文章中,我们介绍了两类JavaScript小工具及其源码:浮动文本和弹出菜单。本文中,我们将继续介绍另外几个有用的JavaScript小工具,并着重说明其工作原理,因此你可以简单修改后应用到自己的程序中。本文中的JavaScript代码应该不用做任何修改就可以在当前所有主流浏览器上运行。所以,不用再费周折……
使用div标签的图片切换(Image Toggling with the div Tag)
很多情况下,你可能想要把网页上的一类东西放在一起,例如图片,但是它们又会占据太多的空间。为什么不只放置一张图片,而让用户使用一个开关在图片之间切换呢?如下:
|
function
ShowImage(page, tag)
...
{
var i = 1;
var el;
while (el = document.getElementById(tag + i)) ...{
if (i == page)
el.style.display = 'block';
else
el.style.display = 'none';
i++;
}
}
<
table
>
<
tr
valign
="top"
>
<
td
>
<
div
style
="display:block"
id
="image1"
>
<
img
src
="/onlamp/2007/08/23/graphics/pic1.jpg"
/>
</
div
>
<
div
style
="display:none"
id
="image2"
>
<
img
src
="/onlamp/2007/08/23/graphics/pic2.jpg"
/>
</
div
>
<
div
style
="display:none"
id
="image3"
>
<
img
src
="/onlamp/2007/08/23/graphics/pic3.jpg"
/>
</
div
>
</
td
>
<
td
width
="100%"
align
="right"
>
<
select
onchange
="ShowImage(parseInt(this.value), 'image');"
>
<
option
selected
="selected"
value
="1"
>
Image 1
</
option
>
<
option
value
="2"
>
Image 2
</
option
>
<
option
value
="3"
>
Image 3
</
option
>
</
select
>
</
td
>
</
tr
>
</
table
>
然后,我们在下拉框的onchange事件发生时调用上面JavaScript函数。当用户在下拉框选择新的项目时就会触发该事件。我们传递两个参数:下拉框本身的引用和包含了所有图片的div标签id基础部分(注意image1、image2和image3都是以image开头)。
函数先获得表示哪一个图片需要显示的选择值。parseInt用来保证保存的是数字而不是字符串。接下来获得第一个div标签的句柄,本例中是id为image1的div。如果这个图片需要显示,就将它的display样式设置为block,其他的设置为none。然后,接着处理下一个标签(image2),等等,直到没有了需要处理的标签,这是退出函数。
因此,只要下拉框中的新选项被选择,其相应的div区域就会显示,而其他的被隐藏。它们在网页上共享同一块区域,因为在HTML中它们一个个紧挨着的。然而,这当然不是一个限制,如果需要我们可以让它们穿过不同的区域,也可以根据不同的选择出现在网页上不同的位置。相似地,我们也没有限制只能是图片;只要是可以放在div标签中的任何东西都可以使用鼠标点击显示或隐藏。这个功能使你可以在页面放置更多的信息,而不需要用户拖动滚动条。
tab:使用div的更多乐趣(Tabs: More Fun with div)
接下来我们看使用div标签的创造性作用的另外一个例子。有时候,需要在页面包含几个tab页。点击一个tab页面,就会显示其包含的信息,隐藏其他的,很像当前一系列的tab类型的web浏览器(译者注:Firefox和IE7都是这种形式)。但是,通常情况下,点击HTML的tab会引起页面的重载,这肯定会打断界面的连贯性。有没有信息可以立即呈现的方法呢?的确要感谢我们在上个例子中学到的小技巧,它可以完成。试一下吧:
Introducing the new, improved multi-widget. It slices, it dices, it even does your taxes! Order yours today! Call now: 555-WIDG
The multi-widget is a sophisticated piece of complex machinery designed by the country's leading nuclear physicists. Order yours today and you will quickly learn how easy it is to do just about anything in no time, thanks to our patented EZ-Widge technology. Motor: 5HP
|
没有什么值得惊奇的,这个例子使用了和上一个完全一样的JavaScript函数,但是实现了一个完全不同的效果。其余的效果有几条简单CSS规则实现。我们先看一下例子中的HTML代码:
<
div
style
="display:block"
id
="tab1"
>
<
ul
class
="tab"
>
<
li
class
="tab_selected"
onclick
="ShowImage(1, 'tab');"
>
Summary
</
li
>
<
li
onclick
="ShowImage(2, 'tab');"
>
Details
</
li
>
<
li
onclick
="ShowImage(3, 'tab');"
>
Known Issues
</
li
>
</
ul
>
<
p
>
Introducing the new, improved multi-widget. It slices, it dices, it even does
your taxes! Order yours today! Call now: 555-WIDG
</
p
>
</
div
>

<
div
style
="display:none"
id
="tab2"
>
<
ul
class
="tab"
>
<
li
onclick
="ShowImage(1, 'tab');"
>
Summary
</
li
>
<
li
class
="tab_selected"
onclick
="ShowImage(2, 'tab');"
>
Details
</
li
>
<
li
onclick
="ShowImage(3, 'tab');"
>
Known Issues
</
li
>
</
ul
>
<
p
>
The multi-widget is a sophisticated piece of complex machinery designed by the
country's leading nuclear physicists. Order yours today and you will quickly
learn how easy it is to do just about anything in no time, thanks to our patented
EZ-Widge technology.
</
p
>
<
p
>
Motor: 5HP
<
br
/>
Dimensions: 8" x 5" x 2"
<
br
/>
Weight: 212 g
<
br
/>
Radioactivity: negligible
</
p
>
</
div
>

<
div
style
="display:none"
id
="tab3"
>
<
ul
class
="tab"
>
<
li
onclick
="ShowImage(1, 'tab');"
>
Summary
</
li
>
<
li
onclick
="ShowImage(2, 'tab');"
>
Details
</
li
>
<
li
class
="tab_selected"
onclick
="ShowImage(3, 'tab');"
>
Known Issues
</
li
>
</
ul
>

<
ul
>
<
li
>
Do not use multi-widget near open flames
</
li
>
<
li
>
Do not run while holding multi-widget
</
li
>
<
li
>
Do not taunt multi-widget
</
li
>
<
li
>
Multi-widget may, under certain as yet undetermined circumstances,
spontaneously explode. We hereby disclaim any libaility for personal injury
caused as a result of multi-widget; for your safety, we recommend wearing
body armor while handling multi-widget.
</
li
>
</
ul
>
</
div
>
每个tab在触发onclick事件时就会调用JavaScript函数ShowImage。就像我们在第一个例子中看到的,这个函数隐藏了除作为参数传递给ShowImage的div之外的其他div区域。因此,我们在这里使用显示点击的tab,隐藏其他的。CSS或者样式用来实际绘制tab。我们定义了两个类:tab和tab_selected。前者应用于整个tab栏,而后者只用于被选择的tab。CSS的代码如下:
ul.tab
{...}
{
margin: 0;
padding: 3px 0;
border-bottom: 1px solid #778;
font-weight: bold;
}


ul.tab li
{...}
{
display: inline;
padding: 3px 0.5em;
margin-left: 3px;
border-top: 1px solid #778;
border-left: 1px solid #778;
border-right: 1px solid #778;
border-bottom: none;
background: top repeat-x #89aac7;
white-space: nowrap;
color: white;
cursor:pointer;
}


ul.tab li.tab_selected
{...}
{
background: #fff;
border-bottom: 1px solid #fff;
color: black;
}
接下来的部分用在tab栏中的所有li标签上。display:inline可能是最重要的,它让列表横向排列代替纵向。还是margin和padding属性让tab排成一行,并且在相邻tab之间留下一定空隙。border属性设置tab的顶部和两边的边线(底部的边线来自ul标签)。最后,设置背景和前景色,确保文字不会换行。
最后一部分之应用于当前选中的tab,覆盖了第二部分中的一些属性设置。改变了tab的背景和前景色,使其突出,同时使用白色的底线掩盖了ul标签的黑色底线。这样就有了选中的tab在其他tab之前的感觉。
在本例中,tab的所有被加载后保存在网页上,所以点击一个tab时几乎是立即呈现其内容,不会引起页面的任何重载。使用一个十分简单的JavaScript函数和一小段CSS,我们就得到了真正令人印象深刻的效果。
div得更多技巧(And Even More div Tricks)
和上一个例子中我们学到有用的应用程序的技巧一样,尝试下面的例子,可以用来作为文本或列表的总结性区域,允许用户只展开和查看他/她感兴趣的内容:
| Choice of four widget colors |
|
|
<
div
style
="display:block;"
id
="colors1"
>
<
table
style
="background:#eeeebb"
>
<
tr
>
<
td
>
<
img
src
="/onlamp/2007/08/23/graphics/expand.jpg"
style
="cursor:pointer;"
alt
="Click to Expand"
title
="Click to Expand"
onclick
="ShowImage(2, 'colors');"
/>
</
td
>
<
td
>
Choice of four widget colors
</
td
>
</
tr
>
</
table
>
</
div
>
<
div
style
="display:none;"
id
="colors2"
>
<
table
style
="background:#eeeebb"
>
<
tr
valign
="top"
>
<
td
>
<
img
src
="/onlamp/2007/08/23/graphics/collapse.jpg"
style
="cursor:pointer;"
alt
="Click to Collapse"
title
="Click to Collapse"
onclick
="ShowImage(1, 'colors');"
/>
</
td
>
<
td
>
<
ul
>
<
li
>
blue
</
li
>
<
li
>
green
</
li
>
<
li
>
red
</
li
>
<
li
>
brown
</
li
>
</
ul
>
</
td
>
</
tr
>
</
table
>
</
div
>
拖拽和切换(Drag and Drop and Swap)
现在,我已经过多的分析和讨论了div标签,下面我们就来看一些不同的东西。在这个例子中,我们展示一个使用鼠标拖拽文本(或图片)的方法。这也可以用来实现JavaScript游戏或者更加重要的目的,例如,允许你更换页面中图片的顺序。在下面的例子中,尝试拖拽三个名字来更换它们的位置。注意,你可以没有任何问题的交换John和Jane,但是却不能交换Bill和另外两个的位置,因为他总是捣乱。
| John |
| Jane |
| Bill |
这个例子比至今为止的其他例子包含更多的代码,但是它仍然是相当易于理解的。和其他例子不同,它使用了全局鼠标事件。特别指出,它依赖于三个回调函数:按下鼠标、移动鼠标和释放鼠标。使用这些类别的全局事件缺点是,如果一次触发多个事件,就会变得非常危险。所以,你应该最小化这些事件的同时使用,在每个页面最多使用一个或者两个。对于这样一个特别例子,全局事件是非常必要的。下面我们每一次只看一部分代码:
//
Set the callbacks
document.onmousedown
=
mousedown;
document.onmousemove
=
movemouse;
document.onmouseup
=
mouseup;
var
lastobj;
//
Last draggable object we hovered over
var
isdrag;
//
True if dragging an object
//
This prevents browsers from highlighting the draggable text
//
when you click on it. The table containing all the draggable
//
text has id drag_drop.
window.onload
=
function
()
...
{
var e = document.getElementById('drag_drop');
if (e) ...{
if (moz)
e.onmousedown = function () ...{ return false; } // mozilla
else
e.onselectstart = function () ...{ return false; } // ie
}
}
//
Checks to see if a swap is allowed between two objects based on their ids.
//
Change this as you see fit to permit or forbid swapping each possible pair
//
of draggable items.
function
allowswap(a,b)
...
{
if (a.id == "dragdropa" && b.id == "dragdropb" || a.id == "dragdropb" && b.id == "dragdropa")
return true;
return false;
}

//
Returns true if an object is draggable - change this to suit your needs.
function
isdraggable(obj)
...
{
if (obj.id.substr(0,8) == "dragdrop")
return true;
return false;
}
//
Callback when mouse button is pressed. This checks if an item is draggable, and
//
if so initiates the process.
function
mousedown(e) 
...
{
var obj = moz ? e.target : event.srcElement;
// Trace up DOM tree to see if item clicked on is draggable. This allows
// for the fact that you may click, for example, on a TD while the enclosing
// TR is the draggable object.
while (obj.tagName != "HTML" && obj.tagName != "BODY" && !isdraggable(obj)) ...{
obj = moz ? obj.parentNode : obj.parentElement;
}
if (isdraggable(obj)) ...{
// If draggable, set a global flag to track this, and save a pointer
// to the object in a global variable as well (dragobj).
isdrag = true;
dragobj = obj;
// origx, origy is original starting location of dragged object
origx = dragobj.style.left;
origy = dragobj.style.top;
// x,y is absolute co-ordinates within the window
x = moz ? e.clientX : event.clientX;
y = moz ? e.clientY : event.clientY;
// While offsetX, offSetY depend on where exactly you clicked on the object.
// Thus if you click in the middle of the object, it will be 'attached' to
// the mouse at that point, and not the upper left corner, for example.
offsetX = moz ? e.layerX + 2: event.x + 2;
offsetY = moz ? e.layerY + 2: event.y + 2;
}
}
假设我们点击了一个可拖拽对象,我们要将全局标志设为true,把对象保存在 dragobj中。我们还要保存几个坐标: dragobj的原始位置、点击时的鼠标相对位置和点击的绝对位置。
//
Callback when mouse is moved. It will change the cursor when you move over an object
//
you can - or cannot - swap with.
function
movemouse(e)
...
{
// Check if we are dragging an object
if (isdrag) ...{
// If so, set the dragged object's position relative to how much the mouse has moved
// since first clicked.
dragobj.style.left = moz ? origx + e.clientX - x + offsetX + 'px' : origx + event.clientX - x + offsetX;
dragobj.style.top = moz ? origy + e.clientY - y + offsetY + 'px' : origy + event.clientY - y + offsetY;
var obj = moz ? e.target : event.srcElement;
// If we are over an element that we cannot swap with, change its cursor style
// to show that a swap is forbidden
if (obj != dragobj && isdraggable(obj) && !allowswap(dragobj,obj)) ...{
obj.style.cursor = 'wait';
// save in a handle to the object in a global so we can reset the cursor later
lastobj = obj;
}
else if (lastobj) // reset the cursor as soon as we move off a non-swappable object
lastobj.style.cursor = 'pointer';
return false;
}
else ...{
// Sometimes can get stuck with no drop icon, so restore cursor just to be safe,
// when not dragging but passing over a draggable item
var obj = moz ? e.target : event.srcElement;
if (isdraggable(obj))
obj.style.cursor = 'pointer';
}
}
注意,作为额外预防措施,如果没有拖拽任何对象将鼠标悬停在可拖拽对象上时,我们仍然将鼠标指针恢复到正常状态。这是因为有时鼠标指针会停留在“等待”状态,也要依赖于用户移动鼠标、释放鼠标按键有多快速,等等。这就是说,上面提到恢复鼠标指针状态的逻辑不是没有道理的。
//
Callback when mouse is released - checks if a swap should occur and
//
returns dragged object to its starting position if not.
function
mouseup(e)
...
{
if (isdrag) ...{ // If something is being dragged
// Get the object over which the mouse button was just released
var obj = moz ? e.target : event.srcElement;
// Check if mouse was release over an object we can swap with
if (obj != dragobj && isdraggable(obj) && allowswap(dragobj, obj)) ...{
// A swap is allowed - swap color, tooltip and contents of the
// dragged object with that it was released over
var htm = obj.innerHTML;
obj.innerHTML = dragobj.innerHTML;
dragobj.innerHTML = htm;
var col = obj.style.color;
obj.style.color = dragobj.style.color;
dragobj.style.color = col;
var titl = obj.title;
obj.title = dragobj.title;
dragobj.title = titl;
// Set the position of the object we were dragging (dragobj) where the
// other object (obj) is located and move obj to the original location
// of dragobj before it was dragged (origx, origy).
dragobj.style.left = obj.style.left;
dragobj.style.top = obj.style.top;
obj.style.left = origx;
obj.style.top = origy;
}
else ...{
// No swap can occur so return dragged object to its starting position
dragobj.style.left = origx;
dragobj.style.top = origy;
}
// Restore cursor to pointer if it was changed in movemouse above
if (lastobj) ...{
lastobj.style.cursor = 'pointer';
}
}
isdrag = false; // Nothing is being dragged now
}
最后,初始化对象非常容易。只需要记住,可拖拽对象的id是由 dragdrop开头的:
<
table
id
="drag_drop"
align
="center"
style
="font-size:150%; color:green; background-color:#88ccff; white-space: nowrap;"
>
<
tr
>
<
td
>
<
span
id
="dragdropa"
style
="cursor: pointer; position: relative; color: #ff0000"
title
="John Doe"
>
John
</
span
>
</
td
>
</
tr
>
<
tr
>
<
td
>
<
span
id
="dragdropb"
style
="cursor: pointer; position: relative; color: #a0522d"
title
="Jane Smith"
>
Jane
</
span
>
</
td
>
</
tr
>
<
tr
>
<
td
>
<
span
id
="dragdropc"
style
="cursor: pointer; position: relative; color: #00aa00"
title
="Bill Schwartz"
>
Bill
</
span
>
</
td
>
</
tr
>
</
table
>
总结
但愿前面的例子已经向你展示了 div的一些创造性方式,可以用来切割或选择性的展示网页的部分内容。拖拽的例子只是十分强大的概念的一个基础例子,在今天多数的高级网页上都可以见到。只需再做一点工作,它就可以用来实现一个完全的可定制主页,例如,你可以拖动和交换新闻feed、图像和更多你内心的内容。唯一的限制,就是你的想象力!

本文介绍几种实用的JavaScript技巧,如图片切换、标签页导航及拖拽功能,通过具体实例讲解如何利用div标签实现这些功能。
2433





