JavaScript_DOM编程艺术第二版学习笔记-第7章

动态创建标记

传统技术:document.write和innerHTML
深入剖析DOM方法:createElement、createTextNode、appendChild和insertBefore。

一、传统方法

1.1 document.write
利用document.write可以在页面上写入内容,但它有着一个很大的缺点就是它违背了“行为与表现分离”的原则。即使将document.write语句挪到外部函数里,也还是需要在标记的body部分使用script标签才能调用那个函数。而将JS和HTML代码混杂在一起既不易阅读和编辑,也无法享受到行为与结构分离的好处。
这样混杂的文档容易导致验证错误。还有,MIME类型application/xhtml+xml与document.write不兼容,浏览器在呈现这种XHTML文档时根本不会执行document.write方法。从某种意义上讲,使用document.write方法有点像使用font标签去设定字体和颜色,虽然在HTML里运行的不错,但不够优雅。
1.2 innerHTML属性
现如今的浏览器几乎都支持innerHTML属性,它并不是W3C DOM标准的组成部分,但已被包含在HTML5规范中。
对于如下testdiv例子:

<div id="testdiv">
    <p>This is <em>my</em> content.</p>
</div>

DOM的视角DOM的视角
DOM提供了关于这个标记非常详细的一幅图画,使用DOM方法和属性可以对任何一个节点进行单独的访问。同样的标记从innerHtml属性的角度看则简单很多,如下:
innerHtml视角这里写图片描述
很显然,innerHtml属性毫无细节可言。要想获得细节就必须使用DOM方法和属性。标准化的DOM像手术刀一样精细,innerHtml属性就象一把大锤那样粗放。当然,如果需要把一大段HTML内容插入网页时,innerHtml更适用。它既支持读取,又支持写入。

<div id="testdiv">
</div>
window.onload = function(){
    var testdiv = document.getElementById("testdiv");
    testdiv.innerHTML = "<p>This is <em>my</em> content.</p>";
}

一样可以在页面上写下内容:This is my content.使用innerHTML,页面的内容将全都被替换。
innerHTML属性要比document.write()方法更值得推荐,使用innerHTML属性,可以把JS代码从标记中分离出来。用不着再在标记的body部分插入script标签。与document.write()方法类似,浏览器在呈现XHTML文档时会直接忽略掉innerHTML属性。

二、DOM方法

DOM是文档的表示,DOM所包含的信息与文档里的信息一一对应,只要学会问正确的问题,使用正确的方法,就可以获取DOM节点树上的任何一个节点的细节。浏览器实际显示的是DOM节点树。明白这个道理,以动态方式创建标记就不那么难以理解了。动态创建标记实则是在改变DOM节点树,从DOM的角度去思考问题。
在DOM看来,一个文档就是一颗节点树。如果想在节点树上添加内容,就必须插入新的节点;如果想添加一些标记,就必须插入元素节点。

2.1 createElement方法

继续使用第一小节的testdiv例子,我们将div设置为空的内容,然后通过动态创建标签的方式写入内容。期望:在div内写入一段文本,内容为:This is my content.

这项任务分两步骤:
1.创建一个新元素
2.把这个元素插入到DOM节点树

首先,我们需要创建标签元素p,用到DOM的createElement方法,createElement的语法是:
document.createElement(nodeName)
下面创建段落标签:document.createElement("p")。这样一个p标签就被创建成功了。
不论何时何地,只要使用了createElement方法,就该把新创建出来的元素附给一个变量:var para = document.createElement("p");
变量para包含着一个指向刚创建出来的p元素的引用,现在新创建出来的元素节点,拥有了自身的DOM属性,但是不在DOM树的任何一个节点上,游荡在JavaScript世界的一个孤儿。

2.2 appendChild方法

把新创建的节点插入某个文档的节点树最简单的方法就是,让这个新节点成为某个现有节点的子节点。具体到testdiv的例子,我们应该让新建的P标签成为div的子节点。这里我们用到appendChild方法,语法是:parent.appendChild(child)
这里我们应该先获取父节点,使用getElementById()的DOM方法,即:
var testdiv = document.getElementById("testdiv"),同样的,我们把查询值赋值给一个变量,方便后面的调用。
有了父节点,事情就好办多了。实现将P节点绑定到testdiv文档中的完整代码如下:

var para = document.createElement("p");
var testdiv = document.getElementById("testdiv");
testdiv.appendChild(para);
2.3 createTextNode 方法

到这步为止,我们已经创建出了一个元素节点并插入到了文档的节点树中,这个节点目前没有任何内容即没有子节点,但是之前的createElement方法只能创建元素节点,并不能创建内容。这里用createTextNode方法来实现它。
createTextNode方法的语法与createElement方法的语法差不多:document.createTextNode("text");
下面是实现创建一个内容为Hello world的文本节点:

var text = document.createTextNode("Hello world");

同样的,现在我们已经创建了一个指向文本内容为”Hello world”文本节点的变量,这个文本节点也不在DOM树节点中,所以我们需要将它成为某个DOM节点的子节点,使得它成为DOM树中一员。这里我们把文本节点绑定到p标签:

var text = document.createTextNode("Hello world");
var para = document.createElement("p");
para.appendChild(text);

到目前为止,我们实现了在页面上有内容显示。完整代码如下:

var text = document.createTextNode("Hello world");
var para = document.createElement("p");
para.appendChild(text);
var testdiv = document.getElementById("testdiv");
testdiv.appendChild(para);
三、进阶
3.1 在已有元素前插入一个新元素

insertBefore()方法将把一个新元素插入到一个现有元素的前面,调用此方法时,必须知道三件事:

  • 新元素(newElement):你想插入的元素
  • 目标元素(targetElement):你想插入到那个元素之前
  • 父元素(parentElement):目标元素的父元素
    parentElement.insertBefore(newElement,targetElement)
    这里父元素可以用parentNode属性值获取。如下,在gallery前面插入placeholder图片:
    gallery.parentNode.insertBefore(placeholder,gallery)
3.2 在已有方法后插入一个新元素

可能你会想,既然有一个insertBefore方法,是否有insertAfter方法,可惜DOM没有提供这个方法。我们依然可以编写实现这个方法。
1.编写insertAfter函数
我们可以用已有的DOM方法和属性编写一个insertAfter函数:

function insertAfter(newElement,targetElement){
    var parent = targetElement.parentNode;//parentElement父元素
    if (parent.lastChild == targetElement){
        parent.appendChild(newElement);
        //如果目标元素是父元素的最后一个子元素,则将新元素成为父元素的子节点(追加到父元素上),按顺序则成为新的最后一个子节点,即成功插入在目标元素之后
    }
    else{
        parent.insertBefore(newElement,targetElement.nextSibling);
        //如果目标元素不是父元素的最后一个子元素,则将新元素插入到目标元素紧挨着的下一个兄弟元素之前。
    }
}

这些函数用到了以下的DOM方法和属性:

  • parentNode属性
  • lastChild属性
  • appendChild方法
  • insertBefore方法
  • nextSibling属性
四、图片库优化

利用上面的知识,我们将图片库的结构、样式和行为彻底分离。JS代码增加了,但标记相应的减少了。图片库文件现在只包含一个由JS脚本和CSS样式表共用的“挂钩”。这个“挂钩”就是图片清单的id属性。实现效果以及完整代码如下:
图片库效果

JS代码

function addLoadEvent(func){
    var oldonload = window.onload;
    if (typeof window.onload != 'function') {
        window.onload = func;
    } else{
        window.onload = function(){
            oldonload();
            func();
        }
    }
}
function insertAfter(){
    var parent = targetElement.parentNode;//parentElement
    if (parent.lastChild == targetElement){
        parent.appendChild(newElement);
        //如果目标元素是父元素的最后一个子元素,则将新元素成为父元素的子节点,按顺序则成为新的最后一个子节点,即成功插入在目标元素之后
    }
    else{
        parent.insertBefore(newElement,targetElement.nextSibling);
        //如果目标元素不是父元素的最后一个子元素,则将新元素插入到目标元素紧挨着的下一个兄弟节点之前。
    }
}
function preparePlaceholder(){
    if (!document.createElement) return false;
    if (!document.createTextNode) return false;
    if (!document.getElementById) return false; 
    if (!document.getElementById('imageallery')) return false;  
    var placeholder = document.createElement('img');
    placeholder.setAttribute("id","placeholder");
    placeholder.setAttribute("src","./../images/b.jpg");
    placeholder.setAttribute("alt","my image");

    var description = document.createElement("p");
    description.setAttribute("id","description");

    var desctext = document.createTextNode("choose an image");
    description.appendChild(desctext);

    var gallery = document.getElementById("imageallery");
    insertAfter(placeholder,gallery);
    insertAfter(description,placeholder);
}

function prepareGallery() {
    if (!document.getElementsByTagName) return false;
    if (!document.getElementById) return false;
    if (!document.getElementById('imageallery')) return false;
    var gallery = document.getElementById('imageallery');
    var links = gallery.getElementsByTagName('a');
    for (var i = 0; i < links.length; i++) {
        links[i].onclick = function() {
            return !showPic(this);
        }
        links[i].onkeypress = links[i].onclick;//对于键盘输入等同于鼠标事件
    };
}

function showPic(whichpic) {
    if (!document.getElementById('placeholder')) return false;
    var source = whichpic.getAttribute("href");
    var placeholder = document.getElementById('placeholder');
    placeholder.setAttribute("src", source);
    // 检查placeholder元素是否存在
    if (placeholder.nodeName != "IMG") return false;    
    if (document.getElementById('description')) {
        var text = whichpic.getAttribute("title") ? whichpic.getAttribute("title") : "";
        var description = document.getElementById("description");
        if (description.firstChild.nodeType == 3) {
            description.firstChild.nodeValue = text;
        }
    }
    return false;
}
addLoadEvent(preparePlaceholder);
addLoadEvent(prepareGallery);

CSS代码

body{
    font-family: "Helvetica","Arial",serif;
    color: #333;
    background-color: #ccc;
    margin: 1em 10%;
}
h1{
    color: #333;
    background-color: transparent;
}
a{
    color: #c60;
    background-color: transparent;
    font-weight: bold;
    text-decoration: none;
}
ul{
    padding: 0;
}
li{
    float: left;
    padding: 1em;
    list-style: none;
}
img{
    display: block;
    clear: both;
    width:80px;
    height:60px;
}
#placeholder{
    width: 400px;
    height: 400px;
}

html代码

<html>

<head>
    <meta charset=utf-8>
    <title>图片库</title>
    <link rel="stylesheet" type="text/css" href="./../styles/showPic.css">
</head>
<body>
    <h1>图片库</h1>
    <ul id="imageallery">
        <li>
            <a href="./../images/11.jpg" onclick="showPic(this); return false;" title="狗狗">
                <img src="./../images/11.jpg">
            </a>
        </li>
        <li>
            <a href="./../images/22.jpg" onclick="showPic(this); return false;" title="花朵">
                <img src="./../images/22.jpg">
            </a>
        </li>
        <li>
            <a href="./../images/a.jpg" onclick="showPic(this); return false;" title="手套">
               <img src="./../images/a.jpg">
            </a>
        </li>
        <li>
            <a href="./../images/border.png" onclick="showPic(this); return false;" title="边框">
                <img src="./../images/border.png">                
            </a>
        </li>
    </ul>
    <img id="placeholder" src="./../images/b.jpg" alt="my image">
    <p id="description">chooese an image</p>
    <script src="./../javascripts/showPic.js"></script>
</body>
</html>
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 《JavaScript DOM编程艺术第二版是一本非常经典的前端开发书籍,由作者Jeremy Keith和Jeffrey Sambells合作编写而成。该书主要介绍了使用JavaScriptDOM技术进行网页开发的知识,涵盖了DOM操作、事件监听、表单验证、AJAX等内容。 本书首先讲解了DOM的基础知识,包括节点、元素、属性、文本等概念,并介绍了通过JavaScriptDOM进行操作的方法。然后,通过实例讲解了如何根据用户的交互行为来实现动态效果,如当用户点击某个按钮时改变网页的背景色等。 此外,本书还介绍了如何利用AJAX技术进行异步数据交互,比如通过JavaScript动态加载内容等。同时,本书也提供了一些工具和技巧来提高网页的性能和用户体验,比如浏览器兼容性、缓存、图片优化等。 总之,《JavaScript DOM编程艺术第二版是一本前端开发必读的书籍,可以帮助读者全面掌握JavaScriptDOM技术,在开发网页时提高效率和质量。而PDF版本的书籍更方便读者随时随地学习,建议前端开发人员可以认真阅读和应用到实践中。 ### 回答2: 《JavaScript DOM编程艺术第二版》是一本深入浅出的JavaScriptDOM编程入门书籍,适合初学者学习。 该书共有18,从JavaScript基础语法和DOM结构开始讲起,一步步引导读者学习JavascriptDOM编程。其中介绍了文档对象模型(DOM)的概念、DOM节点、节点属性与操作等重要知识点,并通过实例和练习帮助读者更好地理解如何使用DOM进行网页设计和开发。此外,书中还介绍了如何使用JavaScript制作动态网页、表单验证、浏览器兼容性问题等实用的开发技巧,为读者提供了丰富的编程经验。 书中使用简洁易懂的语言,结合大量实例和练习,让读者可以快速掌握JavaScriptDOM的核心概念和编程技巧。作者还在书中提供了很多实战案例,让读者可以将所学的知识应用到实际开发中,并且让读者更好地理解如何进行项目开发。 总之,《JavaScript DOM编程艺术第二版》是一本不可多得的优秀JavaScriptDOM编程入门教材,读者只需要具备基本的JavaScript和HTML/CSS知识,即可轻松掌握书中内容,快速提高前端开发能力。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值