Javascript DOM 编程艺术:ENHANCING CONTENT
2012-08-27 02:41 youxin 阅读(783) 评论(0) 编辑 收藏 举报作者首先提出问题:对于标签(markup)中的属性(attribute)来说,不同浏览器往往有不同的处理方法。比如 <img alt="..." title="..."/>,有些浏览器把 alt 属性当做 tooltip,但有些则把 titile 当做 tooltip。总的来说就是,当一个标签中有 attr 时,你就得听不同浏览器的摆布,它说怎么干就怎么干。为了从它手中夺回这个权利,我们可以使用一些 JS 代码来进行处理。
作者举出了第一个实例,为一篇 web 页面动态创建缩略语(abbreviation)的列表。大家知道,我们可以使用 <abbr>...</abbr> 来指示一个缩略语,如 <abbr title="Document Object Model">DOM</abbr>,(chrome当鼠标放在字体上面时,会显示内容)。其中 title 属性指明了缩略语的全称。
文字如下:
<h1>What is the Document Object Model?</h1> <p> The <abbr title="World Wide Web Consortium">W3C</abbr> defines the <abbr title="Document Object Model">DOM</abbr> as: </p> <blockquote cite="http://www.w3.org/DOM/"> <p> A platform- and language-neutral interface that will allow programs and scripts to dynamically access and update the content, structure and style of documents. </p> </blockquote> <p> It is an <abbr title="Application Programming Interface">API</abbr> that can be used to navigate <abbr title="HyperText Markup Language"HTML</abbr> and <abbr title="eXtensible Markup Language">XML </abbr> documents. </p>
The title attributes for the abbreviations in the document are hidden. Some browsers
will display the titles as tool tips when you mouse over the abbreviations. The default
browser behavior for abbreviations is as unpredictable as the default browser styling.
In the same way that you can override the default styles with CSS, you can override the
default behavior with the DOM。
Displaying abbreviations
It would be nice to gather all the title values from the <abbr> tags and display them on
the page. A definition list would be the perfect way to display the titles and the values
contained in the <abbr> tags. This is how the definition list would be written:
<dl> <dt>W3C</dt> <dd>World Wide Web Consortium</dd> <dt>DOM</dt> <dd>Document Object Model</dd> <dt>API</dt> <dd>Application Programming Interface</dd> <dt>HTML</dt> <dd>HyperText Markup Language</dd> <dt>XML</dt> <dd>eXtensible Markup Language</dd> </dl>
我们首先下一个函数,提取abbr里面的title属性和<abbr> </abbr>里面的内容:
function displayAbbreviations() { var abbreviations=document.getElementByTagName("abbr"); if (abbreviations.length < 1) return false; var defs = new Array(); for (var i=0; i<abbreviations.length; i++) { var definition = abbreviations[i].getAttribute("title"); var key=abbreviations[i].lastChild.nodeValue; defs[key] = definition; } }
Creating the markup
A definition list is the ideal way to structure a list of abbreviations and their meaning.
A definition list (<dl>) contains a series of definition titles (<dt>) and definition descriptions
(<dd>):
<dl>
<dt>Title 1</dt>
<dd>Description 1</dd>
<dt>Title 2</dt>
<dd>Description 2</dd>
</dl>
var dlist = document.createElement("dl");
for (key in defs) { var definition = defs[key]; var dtitle = document.createElement("dt"); var dtitle_text = document.createTextNode(key); dtitle.appendChild(dtitle_text);
var ddesc = document.createElement("dd"); var ddesc_text = document.createTextNode(definition); ddesc.appendChild(ddesc_text);
dlist.appendChild(dtitle); dlist.appendChild(ddesc); }
At this stage, your definition list is complete. It exists in JavaScript as a DocumentFragment.现在是一个documentFragment。All that remains for you to do is to insert it into the document.
Rather than inserting the list of abbreviations unannounced, it would be a good idea to
place them under a descriptive heading.
Create an h2 element node:
var header = document.createElement("h2");
Create a text node with the value “Abbreviations”:
var header_text = document.createTextNode("Abbreviations");
Place the text node inside the element node:
header.appendChild(header_text);
完整代码如下:
<html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>无标题文档</title> <style> body { font-family: "Helvetica","Arial",sans-serif; font-size: 10pt; } abbr { text-decoration: none; border: 0; font-style: normal; color:red; } </style> <script> function displayAbbreviations() { var abbreviations=document.getElementsByTagName("abbr"); if (abbreviations.length < 1) return false; var defs = new Array(); for (var i=0; i<abbreviations.length; i++) { var definition = abbreviations[i].getAttribute("title"); var key=abbreviations[i].lastChild.nodeValue; defs[key] = definition; } var dlist = document.createElement("dl"); for(key in defs) { var definition=defs[key]; var dtitle=document.createElement("dt"); var dtitle_text=document.createTextNode(key); dtitle.appendChild(dtitle_text); var ddesc=document.createElement("dd"); var ddesc_text=document.createTextNode(definition); ddesc.appendChild(ddesc_text); dlist.appendChild(dtitle); dlist.appendChild(ddesc); } var header=document.createElement("h2"); var header_text=document.createTextNode("Abbreviations"); header.appendChild(header_text); document.body.appendChild(header); document.body.appendChild(dlist); } window.onload=displayAbbreviations; </script> </head> <body> <h1>What is the Document Object Model?</h1> <p> The <abbr title="World Wide Web Consortium">W3C</abbr> defines the <abbr title="Document Object Model">DOM</abbr> as: </p> <blockquote cite="http://www.w3.org/DOM/"> <p> A platform- and language-neutral interface that will allow programs and scripts to dynamically access and update the content, structure and style of documents. </p> </blockquote> <p> It is an <abbr title="Application Programming Interface">API</abbr> that can be used to navigate <abbr title="HyperText Markup Language">HTML</abbr> and <abbr title="eXtensible Markup Language">XML</abbr> documents. </p> </body> </html>
Displaying citations
The blockquote element contains an attribute called cite. This is an optional attribute
you can use to specify a URL where the contents of the blockquote can be found.
In theory, this is a useful way of linking quotes with relevant web pages. In practice,
browsers tend to ignore the cite attribute completely. The information is there but it isn’t
being acted upon. Using JavaScript and the DOM, you can take that information and display
it in a more meaningful way.
Here is a plan of action for displaying these kind of citations as links:
1. Loop through all the blockquote elements in the document.
2. Get the value of the cite attribute from the blockquote.
3. Create a link with the text “source”.
4. Give this link the value of the cite attribute from the blockquote.
5. Insert this link at the end of the quoted text.
function displayCitations() {
var quotes = document.getElementsByTagName("blockquote");
for (var i=0; i<quotes.length; i ++) {
if (!quotes[i].getAttribute("cite")) {
continue;
}
var url = quotes[i].getAttribute("cite");
Finding your element
A blockquote element must contain block level elements, such as paragraphs, to contain
the text being quoted. You want to place the link at the end of the last child element node
contained by the blockquote element. The obvious thing to do is find the lastChild
property of the current blockquote element:
quotes[i].lastChild
But if you do this, you could potentially run into a problem. Take a look at the markup
again:
<blockquote cite="http://www.w3.org/DOM/">
<p>
A platform- and language-neutral interface that will allow programs
➥and scripts to dynamically access and update the
➥content, structure and style of documents.
</p>
</blockquote>
At first glance, it appears as though the last child of the blockquote element is the p element.You might expect the lastChild property to return the p element node. In reality, this won’t necessarily be the case.It’s true that the paragraph is the last element node contained by the blockquote
element. However, between the end of the p element and the end of the blockquote element,
there is a line break. Some browsers will treat this line break as a text node. That
means that the lastChild property of the blockquote element node isn’t the p element
node, it’s a text node.
A common mistake in DOM Scripting is assuming that a node is an element
node. When in doubt, always check the nodeType value. There are certain methods
that can only be performed on element nodes. If you try to perform them on
text nodes, you could get an error.
It would be great if there was a DOM property called lastChildElement in addition to the
existing lastChild property. Unfortunately, there isn’t. However, using existing DOM
methods, you can write some statements to perform the required task.
You can find all the element nodes within the current blockquote. If you use
getElementsByTagName with the wildcard character (*), it will return every element
regardless of its tag name:
var quoteChildren = quotes[i].getElementsByTagName("*");
The variable quoteElements is an array containing all the element nodes contained by the
current blockquote element, quotes[i].
var elem = quoteChildren[quoteChildrens.length - 1];
The variable elem refers to the last element node within the blockquote.
Getting back to your loop in the displayCitations function, this is what you’ve got so far:
for (var i=0; i<quotes.length; i++) { if (!quotes[i].getAttribute("cite")) continue; var url = quotes[i].getAttribute("cite"); var quoteChildren = quotes[i].getElementsByTagName('*'); var elem = quoteChildren[quoteChildren.length - 1];
Rather than assuming that quoteChildren will return an array of element nodes, run a little
check to see if its length is less than one. If that’s the case, use the continue keyword again
to break out of the current loop:
for (var i=0; i<quotes.length; i++) { if (!quotes[i].getAttribute("cite")) continue; var url = quotes[i].getAttribute("cite"); var quoteChildren = quotes[i].getElementsByTagName('*'); if (quoteChildren.length < 1) continue; var elem = quoteChildren[quoteChildren.length - 1];
完整代码如下:
function displayCitations() { var quotes = document.getElementsByTagName("blockquote"); for (var i=0; i<quotes.length; i ++) { if(!quotes[i].getAttribute("cite")) continue; var url=quotes[i].getAttribute("cite"); var quoteChildren = quotes[i].getElementsByTagName('*'); if(quoteChildren.length<1) continue; var elem = quoteChildren[quoteChildren.length - 1]; var link = document.createElement("a"); var link_text = document.createTextNode("source"); link.appendChild(link_text); link.setAttribute("href",url); link.setAttribute("target","_blank");
var superscript = document.createElement("sup"); superscript.appendChild(link); elem.appendChild(superscript); } }
<sup><a href="http://www.w3.org/DOM/">source</a></sup>
The markup
The accesskey attribute associates an element, such as a link, with a specific key on a keyboard.
This can be useful for people who don’t navigate with a mouse. If you are visually
impaired, for instance, it’s very handy to have keyboard shortcuts.
On many Windows browsers, you can press ALT + accesskey; on many Mac browsers, you
can press CTRL + accesskey.
Here’s an example of an accesskey attribute:
<a href="index.html" accesskey="1">Home</a>
It’s usually not a good idea to use too many access keys. There is a danger that they could
clash with the keyboard shortcuts built into the browser.
A loose convention has arisen for some basic accesskey settings. Have a look at
http://www.clagnut.com/blog/193/. An accesskey value of one is used for a link back to
the home page of a site. An accesskey value of two is used for “skip navigation” links. An
accesskey value of four is used for a link to a search form or page. An accesskey value of
nine is used for a link to contact information. An accesskey value of zero is used for a link
to an accessibility statement.