零js基礎 | 程序設計 | 12 - DOM2和DOM3

var supportsDOM2Core = document.implementation.hasFeature("Core", "2.0");
var supportsDOM3Core = document.implementation.hasFeature("Core", "3.0");
var supportsDOM2HTML = document.implementation.hasFeature("HTML", "2.0");
var supportsDOM2Views = document.implementation.hasFeature("Views", "2.0");
var supportsDOM2XML = document.implementation.hasFeature("XML", "2.0");

混合svg写法

<html xmlns="http://www.w3.org/1999/xhtml">

<head>
    <title>Example XHTML page</title>
</head>

<body>
    <svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 100 100" style="width:100%; height:100%">
        <rect x="0" y="0" width="100" height="100" style="fill:red" />
    </svg>
</body>

</html>

在DOM2 级中,Node 类型包含下列特定于命名空间的属性。
localName:不带命名空间前缀的节点名称。
namespaceURI:命名空间URI 或者(在未指定的情况下是)null。
prefix:命名空间前缀或者(在未指定的情况下是)null。

nodeName 等于prefix+":"+ localName

<html>元素來說

localName:html
tagName:html
namespaceURI:http://www.w3.org/1999/xhtml
prefix:null

<s:svg>元素

localName:svg
tagName:s:svg
namespaceURI:http://www.w3.org/2000/svg
prefix:s

DOM3 级在此基础上更进一步,又引入了下列与命名空间有关的方法。

isDefaultNamespace(namespaceURI):在指定的namespaceURI 是当前节点的默认命名空
间的情况下返回true。
lookupNamespaceURI(prefix):返回给定prefix 的命名空间。
lookupPrefix(namespaceURI):返回给定namespaceURI 的前缀。

Document变化

只有在文档中存在两个或多个命名空间时,这些与命名空间有关的方法才是必需的。

        //创建一个新的SVG 元素
        var svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
        //创建一个属于某个命名空间的新特性
        var att = document.createAttributeNS("http://www.somewhere.com", "random");
        //取得所有XHTML 元素
        var elems = document.getElementsByTagNameNS("http://www.w3.org/1999/xhtml", "*");

Element变化

getAttributeNS(namespaceURI,localName):取得属于命名空间namespaceURI 且名为
localName 的特性。

getAttributeNodeNS(namespaceURI,localName)
getElementsByTagNameNS(namespaceURI, tagName)
hasAttributeNS(namespaceURI,localName)
removeAttriubteNS(namespaceURI,localName)
setAttributeNS(namespaceURI,qualifiedName,value)
setAttributeNodeNS(attNode)

除了第一个参数之外,这些方法与DOM1 级中相关方法的作用相同;第一个参数始终都是一个命
名空间URI。

NamedNodeMap变化
getNamedItemNS(namespaceURI,localName)取得属于命名空间namespaceURI 且名为
localName 的项。
removeNamedItemNS(namespaceURI,localName)

其它变化:

  1. DocumentType 类型的变化 类型新增了3 个属性:publicId、systemId 和internalSubset。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">

中的:publicId == "-//W3C//DTD HTML 4.01//EN",
systemId =="http://www.w3.org/TR/html4/strict.dtd"

alert(document.doctype.publicId);
alert(document.doctype.systemId);
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
[<!ELEMENT name (#PCDATA)>] >
document.doctype.internalSubset //"<!ELEMENT name (#PCDATA)>"
  1. Document 类型的变化
    importNode()
  2. Node 类型的变化
    isSupported()

与DOM1级为document.implementation 引入的hasFeature()方法类似,isSupported()方法用于确定当前节点具有什么能力

if (document.body.isSupported("HTML", "2.0")){
//执行只有"DOM2 级HTML"才支持的操作
}

DOM3 额外引入数据:setUserData(要设置的键,实际的数据(可以是任何数据类型),处理函数)

var value = document.body.getUserData("name");

//创建div
var div = document.createElement("div");

//添加数据
div.setUserData("name", "Nicholas", function(operation, key, value, src, dest) {
    if (operation == 1) {
        dest.setUserData(key, value, function() {});
    }
});

//使用cloneNode复制时,会调用处理函数,从而将数据自动复制到副本
var newDiv = div.cloneNode(true);

//调用getUserData()时,返回与原始结点相同的值
alert(newDiv.getUserData("name")); //"Nicholas"
  1. 框架的变化
var iframe = document.getElementById("myIframe");
var iframeDoc = iframe.contentDocument; //在IE8 以前的版本中无效

兼容

对象,可以使用下列代码。
var iframe = document.getElementById("myIframe");
var iframeDoc = iframe.contentDocument || iframe.contentWindow.document;

cssText
在写入模式下,赋给cssText 的值会重写整个style 特性的值;也就是
说,以前通过style 特性指定的样式信息都将丢失。例如,如果通过style 特性为元素设置了边框,
然后再以不包含边框的规则重写cssText,那么就会抹去元素上的边框。下面是使用cssText 属性的

var div = document.getElementsByTagName('div')[0]
div.style.cssText = 'width:25px;height:100px;background-color:red'

console.log(div.style.cssText)  //width:25px;height:100px;background-color:red

for (var i = 0; i < div.style.length; i++) {

    alert(div.style[i]) //width/height/backgorund-color

    alert(div.style.item(i))

    console.log(div.style.getPropertyValue(div.style[i])) //25px 100px red

}

getPropertyValue()方法取得的始终都是CSS 属性值的字符串表
getPropertyCSSValue()它返回一个包含两个属性的CSSValue 对象,这两个属性分,别是:cssText 和cssValueType。

div.style.removeProperty('width') //移除

getComputedStyle() 要取得樣式的元素與一個為元素字條串如:after,第二個參數可以為null;

無論樣式表還是行間樣式;計算後的值

        var myDiv = document.getElementById("myDiv");
        var computedStyle = document.defaultView.getComputedStyle(myDiv, null);
        alert(computedStyle.backgroundColor); // "red"
        alert(computedStyle.width); // "100px"
        alert(computedStyle.height); // "200px"
        alert(computedStyle.border); // 在某些浏览器中是"1px solid black"

IE下

      var myDiv = document.getElementById("myDiv");
        var computedStyle = myDiv.currentStyle;
        alert(computedStyle.backgroundColor); //"red"
        alert(computedStyle.width); //"100px"
        alert(computedStyle.height); //"200px"
        alert(computedStyle.border); //undefined

綜合

function getStyle(obj, attr) {
    if (obj.currentStyle) {
        return obj.currentStyle[attr]
    } else {
        return getComputedStyle(obj, false)[attr]
    }
};
function getStyleSheet(element){
return element.sheet || element.styleSheet;
}
//取得第一个<link/>元素引入的样式表
var link = document.getElementsByTagName("link")[0];
var sheet = getStyleSheet(link);
var sheet = document.styleSheets[0];
var rules = sheet.cssRules || sheet.rules; //取得规则列表
var rule = rules[0]; //取得第一条规则
alert(rule.selectorText); //"div.box"
alert(rule.style.cssText); //完整的CSS 代码
alert(rule.style.backgroundColor); //"blue"
alert(rule.style.width); //"100px"
alert(rule.style.height); //"200px"
<style>.box{width:100px;}</style>   ----sheet = document.styleSheets[0];
<link rel="stylesheet" href="style.css">----sheet = document.styleSheets[1];
<style>.box{height}</style> --sheet = document.styleSheets[2];


var rules = sheet.cssRules || sheet.rules; //取得规则列表
為每一個sheet裏的每一條;{}裏算一條

必须要注意的是,以这种方式修改规则会影响页面中适用于该规则的所有元素。换句话说,如果有两个带有box 类的

元素,那么这两个元素都会应用修改后的样式。

var sheet = document.styleSheets[0];
var rules = sheet.cssRules || sheet.rules; //取得规则列表
var rule = rules[0]; //取得第一条规则
rule.style.backgroundColor = "yellow"
        function getTop(o) {
            var oTop = o.offsetTop;
            var current = o.offsetParent;

            while (current !== null) {
                oTop += current.offsetTop;
                current = current.offsetParent;
            }
            return oTop;
        }
        alert(getTop(box))

所以视口

        function getViewport() {
            if (document.compatMode == "BackCompat") {
                return {
                    width: document.body.clientWidth,
                    height: document.body.clientHeight
                };
            } else {
                return {
                    width: document.documentElement.clientWidth,
                    height: document.documentElement.clientHeight
                };
            }
        }
        console.log(getViewport())

scrollHeight/scrollWidth/scrollLeft/scrollTop

有些元素(例如<html>元素),即使没有执行任何代码也能自动地添加滚动条;但另外一些元素,则需要通过CSS 的
overflow 属性进行设置才能滚动
scrollWidth 和scrollHeight 主要用于确定元素内容的实际大小

无滚动条时:scrollWidth = clientWidth

实际页面大小:document.documentElement.scrollHeight

视口大小:document.documentElement.clientHeight

无滚动条时:
IE7 chrome

document.documentElement.scrollHeight(页面占用元素大小) < document.documentElement.clientHeight(视口大小)

IE8 /IE9 /IE10 /IE11 firfox

document.documentElement.scrollHeight == document.documentElement.clientHeight

getBoundingClientRect()返回矩形,ie8(2.2),ie9(0,0)

,right 和left 的差值与offsetWidth 的值相等,而bottom 和top 的差值与offsetHeight
相等。而且,left 和top 属性大致等于使用本章前面定义的getElementLeft()和getElementTop()
函数取得的值

function getBoundingClientRect(element) {
    var scrollTop = document.documentElement.scrollTop;
    var scrollLeft = document.documentElement.scrollLeft;
    if (element.getBoundingClientRect) {
        if (typeof arguments.callee.offset != "number") {
            var temp = document.createElement("div");
            temp.style.cssText = "position:absolute;left:0;top:0;";
            document.body.appendChild(temp);
            arguments.callee.offset = -temp.getBoundingClientRect().top - scrollTop;
            document.body.removeChild(temp);
            temp = null;
        }
        var rect = element.getBoundingClientRect();
        var offset = arguments.callee.offset;
        return {
            left: rect.left + offset,
            right: rect.right + offset,
            top: rect.top + offset,
            bottom: rect.bottom + offset
        };
    } else {
        var actualLeft = getElementLeft(element);
        var actualTop = getElementTop(element);
        return {
            left: actualLeft - scrollLeft,
            right: actualLeft + element.offsetWidth - scrollLeft,
            top: actualTop - scrollTop,
            bottom: actualTop + element.offsetHeight - scrollTop
        }
    }
}

alert(getBoundingClientRect(div).left)
alert(getBoundingClientRect(div).right)
alert(div.offsetWidth)
`
DOM2 级遍历和范围

检测是否有DOM2级能力(IE8返回false)

var supportsTraversals = document.implementation.hasFeature("Traversal", "2.0");
var supportsNodeIterator = (typeof document.createNodeIterator == "function");
var supportsTreeWalker = (typeof document.createTreeWalker == "function");

从document 开始依序向前,向下遍历,到开始根节点为止。NodeIterator
和TreeWalker 都以这种方式执行遍历。
    createNodeIterator(root[起点],whatToShow[哪些节点数字代码],filter[NodeFilter对象,一个表示接受或拒绝的特定节点],entityReferenceExpansion[布尔值,表示是否扩展实体引用])

DOM2-----------------------------待放






零js基礎 | 程序設計 | 11 - DOM扩展

DOM扩展

    var div = document.querySelector('#div')

    //返回NodeList實例
    var div = document.querySelectorAll('.divClass')

    console.log(div.item(0))
    console.log(div[0])
    console.log(div)

matchesSelector(CSS選擇符),如果匹配 true,否則 false

if (matchesSelector(div[0], '#div.divClass')) {
    alert(true)
}
//兼容性
function matchesSelector(element, selector) {
    if (element.matchesSelector) {
        return element.matchesSelector(selector);
    } else if (element.msMatchesSelector) {
        return element.msMatchesSelector(selector);
    } else if (element.mozMatchesSelector) {
        return element.mozMatchesSelector(selector);
    } else if (element.webkitMatchesSelector) {
        return element.webkitMatchesSelector(selector);
    } else {
        throw new Error("Not supported.");
    }
}

支持Element Traversal 规范的浏览器有IE 9+、Firefox 3.5+、Safari 4+、Chrome 和Opera 10+。

 childElementCount:返回子元素(不包括文本节点和注释)的个数。
 firstElementChild:指向第一个子元素;firstChild 的元素版。
 lastElementChild:指向最后一个子元素;lastChild 的元素版。
 previousElementSibling:指向前一个同辈元素;previousSibling 的元素版。
 nextElementSibling:指向后一个同辈元素;nextSibling 的元素版。

二、困扰你我的NodeList与HTMLCollection      
  相同点:

    1. 类数组。有length属性,可以用下标索引来访问其中的元素,但没有Array的slice等方法;

    2. 只读。无法增删其中的元素;

    3. 实时同步DOM树的变化。若DOM树有新元素加入,该类型的对象也会将新元素包含进来;

    4. 可通过下标数字类型索引获取集合中指定位置的元素;

    5. 可通过item({String | Number} 索引)方法获取集合中指定位置的元素,若通过索引找不到元素,则以第一个元素作为返回值。

  不同点(主要表现在HTMLCollection比NodeList能力更强大):

    1. HTMLCollection对象可通过namedItem({String} id或name)获取首个匹配的元素,若没有则返回null;

    2. HTMLCollection对象可通过点方式获取第个id或name匹配的元素,若没有则返回undefined。

  各浏览器选择器返回类型差别:

        
        console.log(div instanceof NodeList)  //true

        //帶有.divClass.username的元素
        var div = document.getElementsByClassName('divClass username')
        console.log(div)

        console.log(div instanceof HTMLCollection) //true;

傳統刪class

        var classNames = div.className.split(/\s+/);
        var pos = -1;
        
        for(var i=0;i<classNames.length;i++){
            if(classNames[i] == 'user'){
                pos = i;
                break;
            }
        }
        classNames.splice(i,1);
        div.className = classNames.join(' ');

classList,IE10+,chrome,firefox

        div[0].classList.remove('username')
        div[0].classList.add('current')
        div[0].classList.toggle('divClass')
        
        
        if(div[0].classList.contains('password') && div[0].classList.contains('disabled')){
            alert(true)
        }

焦点管理

var btn = document.getElementById('myButton')
btn.focus()
alert(document.activeElement == btn) //true 

//文档加载完成时,document.activeElement保存的是document.body引用

//确定文档是否获得了焦点
alert(document.hasFocus()) //true

HTMLDocument的变化
1、readyState 两个值 loading:正在加载;complete:已经完成

if(document.readyState == 'complete'){
    
}

2、document.compatMode 的
值等于"CSS1Compat",而在混杂模式下,document.compatMode 的值等于"BackCompat"。

if (document.compatMode == "CSS1Compat") {
    alert("Standards mode");
} else {
    alert("Quirks mode");
}

3、head属性
Chrome 和Safari 5。

var head = document.head || document.getElementsByTagName("head")[0];

字符集属性

alert(document.charset); //"UTF-16"
document.charset = "UTF-8";

defaultCharset,表示根据默认浏览器及操作系统的设置,当前文档默认的字符集
应该是什么

if (document.charset != document.defaultCharset){
alert("Custom character set being used.");
}

自定义数据属性
data-,通过dataset访问 ,dataset是DOMStringMap的一个实例,每个data-name形式的属性都会有一个对应的属性,
比如,自定义属性是data-myname,
那映射中对应的属性就是myname)

<div id="myDiv" data-appId="12345" data-myname="Nicholas"></div>
        var div = document.getElementById('myDiv')
        
        //获取
        var appId = div.dataset.appId;
        var myName = div.dataset.myname;
        //设置
        div.dataset.appId = 123456
        div.dataset.myname = 'elmok'
        
        if(div.dataset.myname){
            alert('hello ' + div.dataset.myname)
        }

插入标记

innerHTML不同浏览器返回的值大小写可能不同
outerHTML返回包括外层
insertAdjacentHTML()两个参数
 "beforebegin",在当前元素之前插入一个紧邻的同辈元素;
 "afterbegin",在当前元素之下插入一个新的子元素或在第一个子元素之前再插入新的子元素;
 "beforeend",在当前元素之下插入一个新的子元素或在最后一个子元素之后再插入新的子元素;
 "afterend",在当前元素之后插入一个紧邻的同辈元素。

<div id="content"></div>
    //作为前一个同辈元素插入
    con.insertAdjacentHTML("beforebegin", "<p>beforebegin!</p>");
    //作为第一个子元素插入
    con.insertAdjacentHTML("afterbegin", "<p>afterbegin!</p>");
    //作为最后一个子元素插入
    con.insertAdjacentHTML("beforeend", "<p>beforeend!</p>");
    //作为后一个同辈元素插入
    con.insertAdjacentHTML("afterend", "<p>afterend!</p>");

之后

<p>beforebegin!</p>
<div id="content">
    <p>afterbegin!</p>
    <p>beforeend!</p>
</div>
<p>afterend!</p>

在使用innerHTML、
outerHTML 属性和insertAdjacentHTML()方法时,最好先手工删除要被替换的元素的所有事件处理
程序和JavaScript 对象属性

for (var i=0, len=values.length; i < len; i++){
ul.innerHTML += "<li>" + values[i] + "</li>"; //要避免这种频繁操作!!
}

//正确做法
var itemsHtml = "";
...

scrollIntoView(),滚动标准作法
如果给这个方法传入true 作为参数,或者不传入任何参数,那么窗口滚动之后会让调用元素的顶部与视口顶部尽可能平齐;
如果传入false 作为参数,调用元素会尽可能全部
出现在视口中,(可能的话,调用元素的底部会与视口顶部平齐。)不过顶部不一定平齐

只有调用才会出现在视口中,类似于a标签本页定位的效果

var btn = document.getElementById('btn')
var div = document.getElementById('content')

btn.onclick = function(){
div.scrollIntoView(true)
}

IE “文档模式”(document mode) 文档模式决定了你可以使用哪个级别的 CSS
要强制浏览器以某种模式渲染页面,可以使用 HTTP头部信息 X-UA-Compatible,或通过等价的 <meta>标签来设置:

//<meta http-equiv="X-UA-Compatible" content="IE=IEVersion"> 

<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7">

    var mode = document.documentMode; 
    alert(mode) // 11/10/9/8/7/5....  

children属性
。IE8及更早版本的 children 属性中也会包含注释节点,但 IE9之后的版本则 只返回元素节点

contains()方法.
经常需要知道某个节点是不是另一个节点的后代

alert(document.documentElement.contains(document.body)); //true
  1. innerText 属性
    outerText 属性 //包括父级也替换

滚动

scrollIntoView()
scrollIntoViewIfNeeded(alignCenter):只在当前元素在视口中不可见的情况下,才滚
动浏览器窗口或容器元素,最终让它可见。如果当前元素在视口中可见,这个方法什么也不做。
如果将可选的alignCenter 参数设置为true,则表示尽量将元素显示在视口中部(垂直方向)。
Safari 和Chrome 实现了这个方法。
 scrollByLines(lineCount):将元素的内容滚动指定的行高,lineCount 值可以是正值,
也可以是负值。Safari 和Chrome 实现了这个方法。
 scrollByPages(pageCount):将元素的内容滚动指定的页面高度,具体高度由元素的高度决
定。Safari 和Chrome 实现了这个方法。
希望大家要注意的是,scrollIntoView()和scrollIntoViewIfNeeded()的作用对象是元素的
容器,而scrollByLines()和scrollByPages()影响的则是元素自身。下面还是来看几个示例吧。

//将页面主体滚动5 行
document.body.scrollByLines(5);
//在当前元素不可见的时候,让它进入浏览器的视口
document.images[0].scrollIntoViewIfNeeded();
//将页面主体往回滚动1 页
document.body.scrollByPages(-1);

由于scrollIntoView()是唯一一个所有浏览器都支持的方法,因此还是这个方法最常用。