前端3DOM编程1

目录

一、DOM树

1、节点类型    2、节点遍历    3、元素节点遍历    4、Document类型

二、节点操作

1、获取节点    2、创建节点    3、修改节点内容    4、插入节点    5、删除节点

三、属性操作

1、property accessor属性访问器    2、getAttribute/setAttribute    3、dataset

四、样式操作

1、更新样式    2、获取样式


文档对象模型(Document Object Model,DOM),用节点对象的方式描述对应的html,是一系列可以操作节点的API规范。DOM在浏览器中通过js实现,可以通过js调API来操作页面结构、样式等。

DOM包括:

DOM Core:DOM核心结构、API的定义;

DOM HTML:定义html如何转化成对象,操作节点、结构;

DOM Style:把样式转化为对象,操作样式;

DOM Event:事件模型,让页面能够响应用户操作。

  

一、DOM树

DOM可以将任何html文档描绘成一个由多层节点构成的树形结构,以文档节点为根结点。

1、节点类型

节点类型由数字常量表示。元素节点ELEMENT_NODE(1)/文本节点TEXT_NODE(3)/DOCUMENT_NODE /COMMENT_NODE/DOCUMENT_TYPE_NODE

if(someNode.nodeType==1){ //判断节点类型,如果是元素节点
    value=someNode.nodeName; //获取元素节点的标签名称
}

2、节点遍历

node.parentNode/firstChild/lastChild/previousSibling/nextSibling,关系指针都是只读的。

node.childNodes获取的是类数组对象,用于保存直接子节点,基于DOM结构动态进行查询的结果。访问某个节点node.childNodes[0]或node.childNodes.item(1)。

node.ownerDocument,指向表示整个文档的文档节点。

function convertToArray(nodes){ //把类数组对象转化为数组,如childNodes、argument
    var array=null;
    try{
        array=Array.prototype.slice.call(nodes,0); //IE8及以下不支持
    }catch(ex){ //手动枚举所有成员
        array=new Array();
        for(var i=0,len=nodes.length;i<len;i++){
            array.push(nodes[i]);
        }
    }
    return array;
}

3、元素节点遍历

element.firstElementChild/lastElementChild/nextElementSibling/previousElementSibling

在IE低版本不支持元素节点,用“节点遍历+节点类型判断”作兼容。

4、Document类型

document对象表示整个html页面,是window对象的属性,可以通过全局的方式直接使用document访问该节点。只有唯一的子元素html。

var html=document.documentElement;
alert(html===document.childNodes[0]); //true
alert(html===document.firstChild); //true

属性:

document.documentElement,指向<html>元素;

document.body,指向<body>元素;

document.title,获取或修改当前文档的标题;

document.referrer,保存着链接到当前页面的那个页面的URL,没有来源则为空字符串,如用于安全判断,如果把不希望直接访问的页面嵌入到其它域名的页面里,则页面被盗链,可进行细微的处理;判断当前页面上游是否在产品内部,如果是别的未知页面,可以把返回按钮替换为首页按钮。

document.URL,返回页面完整的URL。

document.domain,只包含页面的域名。将两个页面的domain设置为相同的值,就可以互相访问对方包含的js对象。

二、节点操作

页面渲染后如何修改页面内容和结构。

<div id="users"> //对这一段html代码进行操作
    <h2>6662人在学习该课程:</h2>
    <ul>
        <li class="user">Satoshi</li>
        <li class="user">春来草青</li>
        <li id="lastUser" class="user last">Kash</li>
    </ul>
</div>

1、获取节点

通过已获取到的节点的节点关系(父子关系、兄弟关系)来获取其它节点,可维护性差,因节点关系紧密,容易获取不到。可以通过接口获取节点。

(1)getElementById

var element=document.getElementById(id);

从文档中通过指定id获取元素,获取到的是包含很多属性和接口的节点对象。因为id在整个文档中,所以通过document调用。

IE8-不区分id大小写,IE7-表单元素的name属性值如果与指定id匹配会被返回,且该方法只返回第一次出现的元素。保证id及表单元素的name在不区分大小写时唯一。

(2)getElementsByTagName

var collection=element.getElementsByTagName(tagName);

通过标签名获取元素,获取element的后代元素中具有指定的标签名称的集合。可以通过下标[]获取该集合中的元素,[]中可以是数值或元素的name值字符串。传入”*”,获取所有后代元素。返回的collection集合是动态的,后续对节点的操作会使该返回值动态变化。

var users=document.getElementById('users');
var a=users.getElementsByTagName('li'); //a.length==3

var lastUser=document.getElementById('lastUser');
lastUser.parentNode.removeChild(lastUser); //a.length==2,a是动态的

(3)getElementsByClassName

var collection=element.getElementsByClassName(className);

通过类名获取元素,空格分隔指定多个类名,获取同时具有这几个类名的元素,类名顺序无关。通过下标获取该集合中的元素。返回的collection集合是动态的。IE8-不支持该方法,作兼容。

users.getElementsByClassName("user")[2]; //li.user.last
users.getElementsByClassName("user last"); //li.user.last
function getElementsByClassName(root,classNames){
    if(root.getElementsByClassName){//特性侦测
        return root.getElementsByClassName(classNames);//优先使用W3C规范
    }else{
        var elements=root.getElementsByTagName('*');//获取所有与后代元素
        var result=[];
        var element,
            classNameStr,
            flag;
        classNames=classNames.split(' ');//拆分类名至数组
        for(var i=0;element=elements[i];i++){
            //选择包含类名的元素
            classNameStr=' '+element.className+' ';
            flag=true;
            for(var j=0,name;name=classNames[j];j++){
                if(classNameStr.indexOf(' '+name+' ')==-1){
                    flag=false;
                    break;
                }
            }
            if(flag){
                result.push(element);
            }
        }
        return result;
    }
}

(4)querySelector/All

var list=element.querySelector/All(selector);

获取指定元素的后代元素中符合选择器的节点,第一个符合条件的元素或所有元素的列表。返回的列表是静态的,一旦获取就不会变化。IE6-7不支持,IE8部分支持。

var users=document.querySelector("#users");
users.querySelectorAll(".user");
document.querySelectorAll("#users .user");

2、创建节点

(1)createElement

var element=document.createElement(tagName);

创建指定标签名的元素。

(2)cloneNode

var deepList=node.cloneNode(true); //深克隆,包括复制节点及其后代节点

var shallowList=node.cloneNode(false); //浅克隆,复制节点本身

克隆,创建调用这个方法的节点的一个完全相同的副本。只复制属性和子节点,不复制添加到DOM节点中的js属性。

3、修改节点内容

(1)textContent

element.textContent

节点及其后代节点的文本内容。IE9-不支持。

user_last.textContent; //"Kash",返回该节点内容
user_last.textContent="Tom"; //修改文本内容

(2)innerText

element.innerText

节点及其后代节点的文本内容,与textContent基本一样。不是W3C规范,但是经常用到,FireFox不支持。作兼容。

if(!('innerText' in document.body)){//特性检测
    HTMLElement.prototype._defineGetter_("innerText",function(){
        return this.textContent;
    });
    HTMLElement.prototype._defineSetter_("innerText",function(s){
        return this.textContent=s;
    });
}

(3)innerHTML

element.innerHTML

给节点添加HTML内容。

users.innerHTML; //返回节点users下面所有的HTML文字
users.innerHTML=""; //删除一批节点

在原来基础上直接增加ul.innerHTML+=’’,相当于重新设置了ul,原来设置的节点事件、样式等被清除。所以需要先创建空的li节点。

var li=document.createElement('li');
li.className='user';
ul.appendChild(li);
//创建节点、插入节点、设置属性
li.innerHTML='<img src="4.jpg">\<a href="/user/4">lifeng</a>';

在低版本的IE有内存泄漏,如上述事件状态被清掉,内存得不到回收。如果填写的是一段代码,直接获取用户信息等,会有安全问题。建议仅用于新结点,且内容是可控的,不是用户填的内容,如果是用户填的内容也要确保其中没有标签。

(4)DocumentFragment

在文档中没有对应的标记,保存将来要添加到文档中的节点,通过appendChild()或insertBefore()批量将文档片段中内容添加到文档中。避免浏览器反复渲染新信息。

//效率不高,每append一次,浏览器都会重复一次ul标签的元素列表
for(var x=0;x<10;x++){
    var li=document.createElement("li");
    li.innerHTML="List item "+x;
    listNode.appendChild(li);
}
//效率提高,把li建立好,批量添加,但仅用于向空元素中添加内容
var html="";
for(var x=0;x<10;x++){
    html+="<li>List item "+x+"</li>";
}
listNode.innerHTML=html;
//效率提高,且不影响已有元素的样式
var frag=document.createDocumentFragment();
for(var x=0;x<10;x++){
    var li=document.createElement("li");
    li.innerHTML="List item "+x;
    frag.appendChild(li);
}
listNode.appendChild(frag);

4、插入节点

(1)appendChild

var achild=element.appendChild(achild);

在元素最后子节点后面插入,并返回新增的节点,element.lastChild==achild。如果添加的节点是已有节点,任何DOM节点不能同时出现在文档不同位置,所以相当于把该节点转移到最后而不是克隆一份。

(2)insertBefore

var achild=element.insertBefore(achild,referenceChild);

把节点插入元素的指定节点之前,并返回新增节点,指定节点是null则插在最后。

var users=document.getElementById('users');
var ul=users.getElementsByTagName('ul')[0]; //[]获得对象的一个元素

var li=document.createElement('li'); //创建节点
li.className='user'; //设置属性
li.innerText='lifeng'; //设置文本内容
//ul.appendChild(li);插入节点
ul.insertBefore(li,ul.firstChild); //插入节点

5、删除节点

(1)removeChild

var child=element.removeChild(child);

移除节点并返回。

var user2=users.getElementsByClassName('user')[1];
user2.parentNode.removeChild(user2);

(2)replaceChild

var achild=element.replaceChild(achild,referenceChild);

返回要替换的节点。

上面四个方法都是操作父节点的子节点,在没有子节点的节点上调用这些方法,会导致错误。

三、属性操作

每个html属性对应相应的DOM对象属性,通过js来获取html属性进行属性操作。

<div>
    <label for="userName">用户名</label>
    <input id="userName" type="text" class="u-txt">
</div>

1、property accessor属性访问器

element.propertyName;

非自定义的属性以属性的形式添加到DOM对象中。通过属性访问符访问的属性是转换过的实用对象,把字符串转换为相应类型,可以直接使用。通用性差,有名字异常,如果属性名与关键字等冲突,需要采用另外的名字;扩展性差,每增加一个html属性,就需要增加DOM属性。

label.htmlFor; //"userName"
input.className; //"u-txt",input是DOM对象
input["id"];//"userName"
input.value='wwq@163.com'; //写操作,在input上增加属性
input.disabled=true; //只有true、false两个取值的属性,无论设置为什么值,只要出现了就是true

2、getAttribute/setAttribute

var attribute=element.getAttribute(attributeName);

element.setAttribute(name,value); //替换值或创建新属性

属性名不区分大小写操作属性字符串。通用性好,没有名字冲突问题;但获取到的都是String类型的字符串,不能直接使用。

input.getAttribute("class");//"u-txt"
input.setAttribute("value","wwq@163.com");
input.setAttribute("disabled","");

3、dataset

element.dataset.propertyName

获取html元素上的自定义属性,这些属性的值都是String型。加data-前缀,用于在元素上保存数据,对应的DOM对象上的属性名将data-和-去掉。

保存跟节点相关的数据用来以后使用。如通过事件显示卡片,数据通过Ajax从后台获取,获取到数据时把数据存在该节点上,当鼠标hover上,把数据填到卡片上。

在低版本IE没有实现,可以用getAttribute()和setAttribute()获取和设置自定义属性兼容。

<div id="user" data-id="123456" data-account-name="hsg"
    data-name="Scott" data-email="476699052@qq.com">hsg</div>

四、样式操作

与用户交互后引起一个或多个元素样式发生变化,通过js来动态修改样式。

整张页面所有的外部、内部样式表对应的DOM对象document.styleSheets;

外部样式表对应的DOM对象element.sheet,link元素对应对象的sheet属性,对应.css外部样式表;

内部样式表对应的DOM对象:element.sheet,style元素对应对象的sheet属性;

内嵌样式对应的DOM对象:element.style。

element.sheet //样式表对应的DOM对象
element.sheet.cssRules[1] //对应第1条CSS属性的声明
element.sheet.cssRules[1].style //style是属性名和属性值的键值对
element.sheet.cssRules[1].style.lineHeight //获取对应的属性值
element.sheet.cssRules[1].selectorText //这条rule的选择器

element.style.color //获取对应的属性值

style对象是CSSStyleDeclaration类的一个对象,是CSS属性名和属性值的键值对。

1、更新样式

(1)增加内嵌样式

在某元素的style属性增加样式,内嵌样式表优先级最高。更新一个属性需要一条语句,且不是我们熟悉的CSS。

element.style.borderColor='red';
element.style.color='red';

一条语句可以更新一个元素所有的CSS属性,具有很强的扩展性,且是熟悉的CSS写法。

element.style.cssText='border-color:red;color:red;';

样式混在逻辑中,在js中写的样式,如果要修改样式,只能在js中修改。

(2)更新class

在元素的class上增加类名。

.invalid{
    border-color:red;
    color:red;
}
element.className+='invalid';

(3)更换样式表

一次更新很多元素样式,如换肤。把style.css拆分成两个CSS。变换皮肤的两个CSS文件中,所有样式选择器相同,后面的属性值不同。

也可以添加或删除样式表来增加或删除样式。

<link rel="stylesheet" href="base.css"> //基本样式
<link id="skin" rel="stylesheet" href="skin.spring.css"> //换肤变化的样式
Util.addEventListener($('change'),'click',changeSkin);
function changeSkin(){
    $('skin').href="skin.summer.css";
}

2、获取样式

(1)element.style

只能获取元素style属性中的样式,获取到的不一定是实际样式值。

(2)window.getComputedStyle()

var style=window.getComputedStyle(element[,pseudoElt]);

获取实际样式,传入当前想获取样式的元素。获取到style对象,只读。IE9-使用element.currentStyle()作兼容。

window.getComputedStyle(element).color;

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值