我们有时候必须使用弹出窗口,所以我们还是要正确使用它。这篇文章会告诉你如何使你的弹窗链接具有可访问性,更可靠,更简洁。
弹窗链接就是点击后会弹出新窗口,并且依赖于Javascript实现。通常情况下,弹出新窗口的链接是通过设置链接标记A的“target”属性为”_blank”来实现的。但是Javascript还是被经常用于实现弹出窗口的特殊效果,或者文档的DOCTYPE不允许“target”属性。
链接基础知识
概念很简单,但是我们要解释一些术语为下面内容作些铺垫:
我们会用到HTML的A标记,并会用到它的”href”和“target”属性。我们还会使用Javascript的“window.open” 方法,并涉及到它的三个参数“url” “name” “features”。下面是这两种方式的类比表格:
| 概念 | a 属性 | window.open 参数 | 说明 |
|---|---|---|---|
| 链接地址 | href | url | 要链接到的地址 |
| 目标窗口 | target | name | 一个显示窗口的标识符 |
| 特殊功能 | N/A | features | 目标窗口的呈现形式(大小、工具栏等) |
糟糕的做法
首先,我们来看一个典型的有问题的html弹窗链接。
<a href=”JavaScript:raw_popup(’http://example.com’);void(0)”>pop me up</a>
这段代码存在两个严重的可用性问题,第一个很明显,不支持Javascript的用户无法实现跳转。
原因很简单,也很愚蠢,链接的地址被写成了一个Javascript函数,而不是实际的url地址。
丑陋的代码
第二个问题不是很明显,但是很具有讽刺意义,当用户本来就打算在新窗口中打开此链接的时候,就会出现无法打开页面的问题。
当我使用右键单击该链接并选择在新窗口或新标签中打开的时候,很明显,浏览器取得这个链接的href属性中的地址,然后填入新窗口的地址栏。但是href属性的地址不是真正的URL而是一段Javascript,所以浏览器无法找到页面。
你可以注意到上面的两个问题全都是源于链接地址的位置被写入了不是地址的Javascript,更好的解决方式就是链接的href属性为真正的链接地址,然后使用一个事件捕捉打开一个弹出窗口,并且设置窗口的各种属性。
下面是一个示例:
<a href=”http://example.com” onclick=”raw_popup(’http://example.com’); return false”>pop me up</a>
为了避免冗余,我们可以把链接对象传给处理函数,来取得其href属性:
<a href=”http://example.com” onclick=”raw_popup(this); return false”>pop me up</a>
不过第一个示例也不是不好,如果你希望给支持和不支持Javascript的用户提供不同的访问地址,就可以使用第一个示例的方式。并且要记住,通过右键新建窗口打开的地址是href属性中的地址而不是Javascript函数中的地址。
如果你希望看到一些强大的Javascript,请不要走开。现在我们做的不是怎样去部署Javascript,而是实现优质的HTML代码。上面的两个示例已经解决了可访问性问题,因为它们的href属性中都是实际的目标地址,这已经足够了,但是我们可以做的更好。
使用HTML完成
我编码的原则是如果HTML能够实现的决不用Javascript,Javascript只是一种对HTML的补充。HTML可以打开链接吗?可以。HTML可以弹出新窗口吗?可以(至少是 transitional DOCTYPE)。HTML可以定义弹出窗口的外观属性吗?不能,这才是Javascript引入的原因。
下面是一个改进的HTML代码。
<a href=”http://example.com” target=”_blank” onclick=”raw_popup(this); return false”>pop me up</a>
加入了target属性后我们可以确保即使用户不支持Javascript也能够在新窗口打开链接,虽然这样无法定制弹出窗口的样式。
部署Javascript
现在我们的HTML很简洁,现在我们的要部署一些Javascript代码了。下面是一些功能完善的弹出窗口脚本:
-
var _POPUP_FEATURES = ‘
-
location=0,
-
statusbar=0,
-
menubar=0,
-
width=400,
-
height=300
-
‘;
-
-
function raw_popup(url, target, features) {
-
if (isUndefined(features)) {
-
features = _POPUP_FEATURES;
-
}
-
if (isUndefined(target)) {
-
target = ‘_blank’;
-
}
-
var theWindow =
-
window.open(url, target, features);
-
theWindow.focus();
-
return theWindow;
-
}
-
-
function link_popup(src, features) {
-
return
-
raw_popup(src.getAttribute(‘href’),
-
src.getAttribute(‘target’) || ‘_blank’,
-
features);
-
}
让我们来仔细看看。
raw_popup是一个”window.open”的增强,使你的工作更简单:
- 更好的默认选项,如果没有定义目标窗口,默认是”_blank”。如果不定义窗口属性,默认属性存在全局变量_POPUP_FEATURES中。
- 焦点:如果弹出窗口已经存在,那么将会被显示在最前。当我们在同一弹出窗口中显示多个页面时,对于使用性而言使窗口显示在最前是正确的方式。
link_popup是专门为使用链接来打开弹出窗口的。它可以获得链接的href属性,和target属性,如果target属性没有定义,那么默认为”_blank”,这使得函数兼容DOCTYPE为strict的文档。
isUndefined函数是一个Js Library中的函数,下面还会用到一些Js Library中的函数。(Js Library),如果你只是想在一个页面中弹出一两个窗口的话,上面已经足够了。如果要进行一些重量级的应用,比如图片相册,CMS系统,那么请继续阅读。
将呈现与逻辑分开
你可能经常听说呈现与逻辑分离是多么多么的重要,是的,这确实很重要。我们回头来看一段HTML代码,有些代码不属于那里,是什么呢?Javascript,没有了onclick。
<a id=”my-popup-link”
href=”http://example.com”
target=”_blank”>pop me up</a>
现在我们必须给那些要弹出窗口的链接增加一个事件监听器,通过Javascript增加监听器要加入下列代码,并且要放在文档的头部。
function event_popup(e) {
link_popup(e.currentTarget);
e.preventDefault();
}listen(’load’, window, function() {
listen(’click’, ‘my-popup-link’, event_popup);
// … other onload statements
}
);
如果你想要给一个文档对象增加事件监听器,这个对象一定要存在于文档树中。当文档加载完毕,将触发window对象的一个load事件。这时我们可以确定文档的所有对象都被加载,我们使用listen给文档对象注册事件处理函数。
listen是一个跨浏览器的addEventListener()的别名部署,它有三个参数:event, elem,func。为了获得elem对象,使用了getElem方法,这个方法也是Js Library中的函数,用来替代getElementById,它即可以获得对象的ID,也可以获得对象本身,也就是可以返回字符串,也可以返回对象。
你会注意到e.currentTarget 和e.preventDefault,IE并不能实现,但是listen 的一个很有用的功能就是,在IE中,将会传递两个虚假的事件对象,来模拟上面的”e”,来实现e.currentTarget 和e.preventDefault。
DOM 也疯狂
通过ID给一个对象增加监听器,在需要弹出窗口很少的时候没有问题。当链接很多的时候,这种方式就会很繁琐。基于这种情况,推荐使用mlisten。
mlisten和listen很类似,不同的是它操作的是一个对象列表,为列表中的每个对象增加监听器。这个列表可以是一个NodeList,或者一个对象数组,ID数组。下面是一个例子:
mlisten(
‘click’,
document.getElementById(’my-link-list’).»
getElementsByTagName(’a'),
event_popup
);
也可以通过classname来获得链接列表,使用Js Library中的getElementsByClass(className [, tagName [, parentNode]]):
mlisten(
‘click’,
getElementsByClass(’popup’,'a’),
event_popup
);
这个函数在一个元素使用多个用空格分开的classname的时候也可以工作,因此你可以用一个classname定义元素的样式,另一个用来指示行为。记住这些操作都要在window.onload中。
一个小问题
在使用监听器的时候,我们不能传递参数给触发函数,这使我们不能为每个链接定义不同的弹出窗口样式?不是的,下面是解决方法。
function event_popup_features(features) {
return function(e) {
link_popup(e.currentTarget, features);
e.preventDefault();
}
}// onload…
listen(
‘click’,
’some-link’,
event_popup_features(’width=300,height=800′)
);
我们通过event_popup_features返回一个函数,这样就可以通过event_popup_features给link_popup传递参数了。