javascript标记
就在几年前,编写HTML的关键技能是了解足够的表格技巧,以说服这两个主要的浏览器或多或少地完成您想要它们执行的操作。 现代Web是一种完全不同的野兽,其中标记的质量是根据您使用标题,段落和列表等结构元素描述内容的程度来判断的。
以前已经多次解释了这种方法的好处:更具可维护性的代码,更小的文件大小,更好的可访问性以及能够从单个样式表控制网站外观的能力,而不必费心散布在多个页面上的庞大的标记块。 很少讨论的一个优点是,结构良好的标记为基于客户端WebJavaScript折腾的第三分支的其他站点增强打开了大门。
本文将研究Javascript和结构良好的标记可以一起工作的两种方式。 第一个示例将展示Java语言如何通过挂钩其cite属性来增强blockquote。 第二个将演示用于构建链接的“最佳品种”脚本,这些链接可切换页面上哪个面板可见。
块引用引文
对于我们的第一个示例,让我们看一下谦虚的blockquote元素。 通常会误用于应用缩进,此元素的正确用法是标记在视觉上应与周围文本分开的引号。 开头的blockquote标记可以采用可选的cite属性,该属性应包含引用在其上的页面的URL。
cite属性的唯一问题是浏览器会完全忽略它。 标记纯粹主义者可能会喜欢它,但是,从纯粹的实际角度来看,使用它并不会带来任何好处,只有在使用正确的标记时才会有自满的满足感。 这就是Java语言的用武之地。使用DOM,可以在具有cite属性的任何blockquote底部添加指向报价源的链接。 这是执行此操作的函数的代码:
function extractBlockquoteCitations() {
var quotes = document.getElementsByTagName('blockquote');
for (var i = 0; i < quotes.length; i++) {
var cite = quotes[i].getAttribute('cite');
if (cite != '') {
var a = document.createElement('a');
a.setAttribute('href', cite);
a.setAttribute('title', cite);
a.appendChild(document.createTextNode('Source'));
var p = document.createElement('p');
p.className = 'blockquotesource';
p.appendChild(a);
quotes[i].appendChild(p);
}
}
}
让我们仔细看一下函数的主体。
var quotes = document.getElementsByTagName('blockquote');
该行使用DOM方法getElementsByTagName
来查找当前页面中的所有blockquote元素,并将它们分配给一个称为引号的数组(实际上是HTMLCollection,但这很方便,这是一种行为类似于数组的数据结构)。
for (var i = 0; i < quotes.length; i++) {
var cite = quotes[i].getAttribute('cite');
if (cite != '') {
现在,我们遍历收集的blockquote节点。 每次,我们使用getAttribute
方法从元素中检索cite属性。 如果设置了cite属性,我们将继续进行有趣的部分:在引号的底部创建一个“源”链接。
var a = document.createElement('a');
a.setAttribute('href', cite);
a.setAttribute('title', cite);
当我们想使用DOM动态地向页面添加新HTML元素时,正确的方法是使用createElement方法以编程方式创建元素。 上面几行创建了一个新的'a'元素,并为其分配了href
和title
属性,两者均设置为引用的URL。
a.appendChild(document.createTextNode('Source'));
我们希望链接元素包含一些用户可以单击以激活链接的文本。 原始文本节点是使用createTextNode
方法创建的。 DOM将HTML元素视为一棵树,因此要将文本添加到我们新创建的链接中,我们需要调用其appendChild
方法。
var p = document.createElement('p');
p.className = 'blockquotesource';
p.appendChild(a);
为了允许我们使用CSS灵活地设置新链接的样式,我们可以将其包装在一个段落元素中。 上面的代码创建了一个这样的元素,将其类设置为' blockquotesource
'以为我们CSS提供一个钩子,然后使用appendChild
将链接添加到该元素。 至此,我们构建的新文档片段等效于以下HTML:
<p class="blockquotesource">
<a href="[cite URL]" title="[cite URL]">Source</a>
</p>
目前,out片段仍然是不可见的,因为尽管我们在内存中创建了片段,但尚未将其附加到文档中。 函数的最后一行就是这样做的:
quotes[i].appendChild(p);
quotes[i]
是我们当前正在处理的blockquote元素。 appendChild
将我们的新段落附加到blockquote上,使其在流程中可见。
还有两个步骤。 首先,我们需要上面的函数在页面首次加载时运行。 有多种方法可以实现这一目标。 最简单的方法是将对函数的调用添加到文档的body元素的onload属性中:
<body onload="extractBlockquoteCitations();">
这很好,但是我们可以做得更好。 由于我们的Javascript函数将托管在一个外部文件中,因此使外部文件也可以正常运行该函数是否有意义? 这样做的天真的方法是使用下面的Java代码行:
window.onload = extractBlockquoteCitations;
请注意,我们提供了函数的名称,但最后忽略了()
,这将导致函数执行。 Javascript支持函数式编程风格,这意味着可以像对待任何其他数据对象一样对待函数,并将其作为参数传递,存储在数据结构中,甚至从其他函数返回。 我将在以后的文章中进一步讨论该主题,但是它的最终结果是将一个函数分配给window.onload
将使其在页面完成加载后执行。
然而,该解决方案也具有缺点。 如果要在给定页面上使用在页面加载完成时执行的多个脚本,则最后一个向window.onload
注册自身的脚本将是唯一要执行的脚本。 真正需要的是一种将我们的函数附加到window对象的onload处理程序而不覆盖现有内容的方法。 不幸的是,Internet Explorer和其他浏览器在处理这种动态事件附件的方式上有所不同。 幸运的是,斯科特·安德鲁(Scott Andrew)发布了一个可以为您处理这些差异的函数。 功能如下:
function addEvent(obj, evType, fn){
if (obj.addEventListener){
obj.addEventListener(evType, fn, false);
return true;
} else if (obj.attachEvent){
var r = obj.attachEvent("on"+evType, fn);
return r;
} else {
return false;
}
}
这是将我们的blockquotes函数添加到window对象的load事件的代码:
addEvent(window, 'load', extractBlockquoteCitations);
最后一步是使用CSS设置报价样式。 这是一个用于处理blockquotes的相对简单CSS代码段:
blockquote {
border-left: 0.25em solid navy;
padding: 0 0.5em;
margin: 0.5em 1.5em 0.5em 2.5em;
}
blockquote p.blockquotesource {
font-weight: bold;
font-size: 0.8em;
text-align: right;
padding-top: 0.5em;
}
![](https://i-blog.csdnimg.cn/blog_migrate/9aedf3f8a37c5bb442afb00955265fd3.png)
免费学习PHP!
全面介绍PHP和MySQL,从而实现服务器端编程的飞跃。
原价$ 11.95 您的完全免费
成品可以在这里查看。
面板切换
现在,让我们考虑一个更高级的动态效果-面板切换器。 此处的目标是在页面上具有多个面板(使用div标记),一次只能看到一个面板。 一组持续可见的链接可用于选择当前显示的面板。 这对于构建类似于选项卡式界面的东西可能有用,该选项卡式界面用于浏览一系列相关屏幕,而无需每次选择一个选项卡时都刷新页面。
每当使用Javascript增强页面时,要记住的一个好规则是,在禁用Javascript的情况下,该页面仍必须可用。 在这种情况下,这意味着理想的解决方案可以在启用Javascript的情况下按广告宣传工作,但会在非Javascript环境中显示页面上的所有面板,每个链接都使用一个直接链接到相关面板URL片段。
那么,这里是可能可行的最简单的标记:
<a href="#p1">Panel 1</a> | <a href="#p2">Panel 2</a>
<div id="p1">This is Panel 1</div>
<div id="p2">This is Panel 2</div>
令人惊讶的是,以上内容几乎是我们为了挂钩某些Javascript来创建所需效果所需要的全部标记。 我们可以继续使用上面的代码,但是让我们在链接中添加一个类以明确声明我们希望对它们做一些特殊的事情:
<a href="#p1" class="toggle">Panel 1</a> |
<a href="#p2" class="toggle">Panel 2</a>
这是Javascript的工作方式。 页面加载后,脚本将扫描页面上的所有链接,以查找类中具有“切换”的任何链接。 对于找到的任何内容,将检查href属性,并将找到在其中指定ID的元素并将其添加到目标元素数组中。 这些元素中除第一个之外的所有元素都将被“关闭”,因此,在页面加载时,只有第一个面板将保持可见。 链接本身将附加有Javascript事件处理程序,以便在激活它们时可以显示其相应的面板。
完整的脚本可以在这里查看。 接下来是代码的工作方式。
var et_toggleElements = [];
第一行创建一个全局空数组,该数组将保存对页面上面板元素的引用。 由于此脚本具有全局变量和许多函数,因此我们将在每个前缀之前加上“ et_
”(以“轻松切换”)-这降低了我们的函数与同一页面加载的其他脚本发生名称冲突的可能性。
/* Initialisation */
function et_init() {
var i, link, id, target, first;
first = true;
for (i = 0; (link = document.links[i]); i++) {
到目前为止,我们已经初始化了一些变量,将first标志设置为true,并开始遍历文档中的所有链接。 使用var声明变量很重要,因为它可以确保变量在函数中是局部的。 没有此步骤,它们将是可全局访问的,并且可能会干扰其他脚本。
if (/btoggleb/.exec(link.className)) {
此条件检查当前链接的类是否具有“ toggle”。 我们使用的是正则表达式,而不仅仅是检查link.className == 'toggle'
,因为class属性可以包含多个以空格分隔的类。 /btoggleb/
是正则表达式; b
部分与“单词边界”匹配,该边界可以是空格,也可以是字符串的开头或结尾。
id = link.href.split('#')[1];
link.href.split('#')
splits the linkhref
at the # mark -- we know that the part we're interested in comes after the #, so we directly index the resulting array with[1]
to pull out the targeted ID.
target = document.getElementById(id);
et_toggleElements[et_toggleElements.length] = target;
在这里,我们做出另一个假设-链接指示的元素实际上存在。 我们使用getElementById()
方法获取该元素,然后通过将其分配给等于数组当前长度的数组索引,将其添加到元素数组中。 之所以可行,是因为数组从0开始索引,但是数组长度从1开始计数; 因此,数组的长度也是数组中下一个空插槽的索引。
if (first) {
first = false;
} else {
target.style.display = 'none';
}
这是我们前面定义的第一个标志使其有用的地方。 我们希望网站上的第一个面板保持可见,而其他面板则使用CSS中等效于' display: none
'的Javascript隐藏。 该标志允许我们执行此操作。
link.onclick = et_toggle;
}
}
}
最后,我们将et_toggle
函数分配给链接的onclick
事件,从而在激活链接时调用该函数。 下一步是定义该功能。
function et_toggle(e) {
if (typeof e == 'undefined') {
var e = window.event;
}
var source;
if (typeof e.target != 'undefined') {
source = e.target;
} else if (typeof e.srcElement != 'undefined') {
source = e.srcElement;
} else {
return true;
}
存在第一段代码是为了弥补Internet Explorer和其他浏览器处理事件的方式之间的另一个差异。 我们需要知道调用该函数时激活了哪个链接,因为这将使我们能够识别应该显示的面板。 上面的代码使用彼得-保罗·科赫(Peter-Paul Koch)对QuirksMode问题的出色解释改编的代码,标识了事件起源的元素并将其放在源变量中:
if (source.nodeType == 3) {
source = targ.parentNode;
}
此处提供了与Safari兼容的代码。 我测试过的所有其他浏览器均返回实际的链接元素作为click事件的源,但Safari却返回了链接内包含的文本节点。 文本节点的nodeType
设置为3(由W3C DOM定义的常数),因此,通过检查此问题,我们可以识别此问题并将目标重置为文本节点的父级,该父级应为链接元素。
var id = source.href.split('#')[1];
同样,我们使用split方法从链接中提取ID。
var elem;
for (var i = 0; (elem = et_toggleElements[i]); i++) {
if (elem.id != id) {
elem.style.display = 'none';
} else {
elem.style.display = 'block';
}
}
现在我们知道了要显示的面板,我们可以循环浏览元素数组,关闭所有ID都与所需面板的ID匹配的元素。
return false;
}
通过返回false,我们可以防止在激活链接时实际跟踪该链接,这可能会导致浏览器中所浏览页面的不希望的跳转。
最后一步是使用前面介绍的addEvent函数将et_init
函数注册到窗口的load事件。
addEvent(window, 'load', et_init);
您可以在此处查看完成的代码。
结论
在本文中,我们看到了两种方法,可以将结构良好的标记与Javascript和W3C DOM配对以达到有用的效果。 我希望本文能启发您寻求使用Javascript和智能标记的新方法。
进一步阅读
还有许多其他基于结构标记的Javascript效果示例。 这里只是一些值得一试的地方:
- Aaron Boodman撰写的Labels.js
http://www.sitepoint.com/article/1206/ - Stuart Langridge的好标题
http://www.kryogenix.org/code/browser/nicetitle/ - Sqart Langridge的aqLists
http://www.kryogenix.org/code/browser/aqlists/ - 由Stuart Langridge排序
http://www.kryogenix.org/code/browser/sorttable/ - 目录由彼得·保罗·科奇(Peter Paul-Koch)
http://www.quirksmode.org/dom/toc.html
翻译自: https://www.sitepoint.com/structural-markup-javascript/
javascript标记