零js基礎 | 程序設計 | 10 - DOM

Node.nodeType == 1 元素节点
Node.nodeType == 2 属性节点
Node.nodeType == 3 文本节点

<head>
    <meta charset="UTF-8">
    <title></title>
</head>

    var h = document.getElementsByTagName('head')[0]
 //   h.nodeType == 1 && console.log('this is an elem')
    h.nodeType == 1 && console.log(h.nodeName) //HEAD

//每个节点都有一个childNodes 属性,其中保存着一个NodeList 对象。即类数组对象
    console.log(h.childNodes[0])
    console.log(h.childNodes[1])
    console.log(h.childNodes[2])
    console.log(h.childNodes[3])
    console.log(h.childNodes[4])

    console.log(h.parentNode)  //5

    console.log(h.childNodes.length)

把NodeTypelist转为数组

function convertToArray(nodes) {
    var array = null;
    try {
        array = Array.prototype.slice.call(nodes, 0); //针对非IE 浏览器
    } catch (ex) {
        array = new Array();
        for (var i = 0, len = nodes.length; i < len; i++) {
            array.push(nodes[i]);
        }
    }
    return array;
}

每个Node都有一个parentNode属性,该属性指向文档树中的父节点;
nodeName //HEAD
parentNode //Html文档结构
childNodes //Nodelists节点集合
previousSibling //前一个
nextSibling //后一个

如果没有子节点,那么firstChild 和lastChild 的值均为null

hasChildNodes(),这个方法在节点包含一或多个子节点的情况下返回true;应该说,这是比查询childNodes
列表的length 属性更简单的方法。

h.hasChildNodes()

ownerDocument,所有节点的共同属性,指向整个文档节点

console.log(h.ownerDocument)

操作节点

末尾:
appendChild()相当于向childNodes列表尾部添加一个节点,,如果是已有节点,则相当于剪切;

中间:
insertBefore(),向childNodes列表放在特定的位置上
insertBefore(要插入的节点,作为参照的节点) 【插入之后按顺序前后排:要插入的节点,作为参照的节点】

插入节点后,被插
入的节点会变成参照节点的前一个同胞节点(previousSibling),

returnedNode = someNode.insertBefore(newNode, null);
alert(newNode == someNode.lastChild); //true

//插入后成为第一个子节点
var returnedNode = someNode.insertBefore(newNode, someNode.firstChild);
alert(returnedNode == newNode); //true
alert(newNode == someNode.firstChild); //true

//插入到最后一个子节点前面
returnedNode = someNode.insertBefore(newNode, someNode.lastChild);
alert(newNode == someNode.childNodes[someNode.childNodes.length-2]); //true

替换:

replaceChild(要插入的节点,要替换的节点)

//替换第一个子节点
var returnedNode = someNode.replaceChild(newNode, someNode.firstChild);

//替换最后一个子节点
returnedNode = someNode.replaceChild(newNode, someNode.lastChild);

移除:
removeChild(要移除的节点)

前面介绍的四个方法操作的都是某个节点的子节点,也就是说,要使用这几个方法必须先取得父节
点(使用parentNode 属性)。另外,并不是所有类型的节点都有子节点,如果在不支持子节点的节点
上调用了这些方法,将会导致错误发生。

共有的节点方法:

cloneNode(true/false),需要再使用 appendChild()/insertBefore()/replaceChild()

normalize() /这个方法唯一的作用就是处理文档树中的文本节点



Document类型

 nodeType 的值为9;
 nodeName 的值为"#document";
 nodeValue 的值为null;
 parentNode 的值为null;
 ownerDocument 的值为 null;
Document 节点的子节点可以是DocumentType、Element、ProcessingInstruction
或Comment,

内置访问子节点的快捷方式:
document.documentElement属性

document.documentElement ==
document.childNodes[0] ==
document.firstChild ==

document.body 属性,直接指向<body>元素;

另一个子节点可能是:(浏览器支持有限)

var doctype = document.doctype; //取得对<!DOCTYPE>的引用

文档信息

document对象属性:

//取得文档标题
var originalTitle = document.title;

//设置文档标题
document.title = "New page title";

//取得完整的URL
var url = document.URL;

//取得域名
var domain = document.domain;

//取得来源页面的URL
var referrer = document.referrer;

IE7下,name與ID相同的不同元素使用doc..ById會返回name的元素

    alert(document.getElementById('myelem').nodeName)

不要讓表單字段的name與其他ID相同

var imgs = document.getElementsByTagName('img')
var imgsname = imgs.namedItem('myimgName')

取得單選按鈕【常用】 getElementByName('color');

特殊集合
document.anchors:包括name屬性的a元素
document.links:包含所有帶href特性的a元素
document.images:包含所img元素
document.forms:包含所form元素

一個element類型:

    console.log(box.nodeType)  //1
    console.log(box.nodeName)  //DIV
    console.log(box.nodeValue) //null
    
    console.log(box.parentNode) //<body......body>
    console.log(box.childNodes) //[elem..text..com...]
    
    console.log(box.tagName) //DIV  tagName == nodeName

HTML元素,可读可写

alert(div.id); //"myDiv""
alert(div.className); //"bd"
alert(div.title); //"Body text"
alert(div.lang); //"en"
alert(div.dir); //"ltr"

取得特性

alert(div.getAttribute("id")); //"myDiv"
alert(div.getAttribute("class")); //"bd"
alert(div.getAttribute("title")); //"Body text"
alert(div.getAttribute("lang")); //"en"
alert(div.getAttribute("dir")); //"ltr"

不存在返回null;

自定义属性应该加上data-前缀以便验证

    var div = document.getElementById('myDiv')
        alert(div.my_special_attribute); //undefined(IE<8 弹 hello ,其它弹undefined)

设置属性:
box.setAttribute('style') //如果不写出错 box.setAttribute('style','')//正确

自定义属性不能简单地使用.来设置

        box.mycolor = 'red';  //使用.设置
        alert(box.getAttribute('mycolor')) //null;(IE9<可弹出)
        
        //setAttributte配套使用;
        box.setAttribute('myspace','300px')
        alert(box.getAttribute('myspace'))

div.removeAttribute("class");完全清除,彻底删除元素特性;

  1. attributes 属性
    Element 类型是使用attributes 属性的唯一一个DOM 节点类型。attributes 属性中包含一个

NamedNodeMap,与NodeList 类似,也是一个“动态”的集合。元素的每一个特性都由一个Attr 节
点表示,每个节点都保存在NamedNodeMap 对象中。NamedNodeMap 对象拥有下列方法

遍历元素特性序列化

function outputAttributes(element) {
    var pairs = new Array(),
        attrName,
        attrValue,
        i,
        len;
    for (i = 0, len = element.attributes.length; i < len; i++) {
        attrName = element.attributes[i].nodeName;
        attrValue = element.attributes[i].nodeValue;
        if (element.attributes[i].specified) {
            pairs.push(attrName + "=\"" + attrValue + "\"");
        }
    }
    return pairs.join(" ");
}

console.log(outputAttributes(box)) // id="box" style="font-size:14px;color:#000" class="boxclass"

创建元素

``javascript

var div = document.body.appendChild('div')
div.id = mydiv
document.body.appendChild(div)

创建文本

var box = document.getElementById('box')
if(box.childNodes[0].nodeType == 3 ){
    alert(123)
}
alert(box.childNodes[0].nodeValue)
alert(box.childNodes[0].data)

Text类型
var e = document.createElement('div')
e.className = 'message'
var atnode = document.createTextNode('fuck ')
e.appendChild(atnode)

var atnode2 = document.createTextNode('world')
e.appendChild(atnode2)


alert(e.childNodes.length) //2  个节点 

e.normalize()  //规范化成1个(合并)
alert(e.childNodes.length) //1

alert(e.firstChild.nodeValue) //fuck world

分割  splitText()
var e = document.createElement('div')
e.className = 'message'

var Tnode = document.createTextNode('hello world')
e.appendChild(Tnode)
document.body.appendChild(e);
var newNode = e.firstChild.splitText(2)
alert(e.firstChild.nodeValue) //he 从2的位置开始分割
comment类型 注释类型 nodeType == 8 
CDATASection类型 XML 文档,表示CDATA区域 nodeType == 4 
DocumentType类型 nodeType == 10
DocumentFragment类型 nodeType == 11;
Attr类型 存在于元素的attributes属性中的节点,nodeType == 11; ??

创建动态脚本:

function loadScript(url) {

var script = document.createElement('script')
script.type = 'text/javascript'
script.src = url
document.body.appendChild(script)

}
loadScript('main.js')


代码执行
function loadScriptString(code) {
    var script = document.createElement('script')
    script.type = 'text/javascript'
    try {
        script.appendChild(document.createTextNode(code))
    } catch (ex) {
        script.text = code;
    }
    document.body.appendChild(script)
}
loadScriptString("function sayHi(){alert('hi')}")`
其实效果跟     eval("function sayName(){alert('name')}")  一样; 

动态样式
function loadStyles(url) {
    var link = document.createElement('link')
    link.rel = 'stylesheet'
    link.type = 'text/css'
    link.href = url
    var head = document.getElementsByTagName('head')[0]
    head.appendChild(link)
}
loadStyles('style.css')

function loadStyleString(css) {

var style = document.createElement('style')
style.type = 'text/css'
try {
    style.appendChild(document.createTextNode(css))
} catch (ex) {
    style.style.cssText = css;
}
document.getElementsByTagName('head')[0].appendChild(style);

}

loadStyleString('body{background:#1F78BF}')

操作表格
cell 11 cell 22
cell 33 cell 44
var table = document.createElement('table')
table.border = 1;
table.width = '100%'

//tbody

var tbody = document.createElement('tbody')
table.appendChild(tbody)

//第一行

tbody.insertRow(0)
tbody.rows[0].insertCell(0);
tbody.rows[0].cells[0].appendChild(document.createTextNode('cell 11'))
tbody.rows[0].insertCell(1);
tbody.rows[0].cells[1].appendChild(document.createTextNode('cell 22'))

//第二行

tbody.insertRow(1)
tbody.rows[1].insertCell(0);
tbody.rows[1].cells[0].appendChild(document.createTextNode('cell 33'))
tbody.rows[1].insertCell(1);
tbody.rows[1].cells[1].appendChild(document.createTextNode('cell 44'))

document.body.appendChild(table)

**HTMLCollection、NodeList以及NamedNodeMap这三个集合都是“动态的”,每当文档发生变化时,他们都会更新。他们将始终保持这最新、最准确的消息。且看以下程序:**
var divs = document.getElementsByTagName('div'),
    i, div;
for (i = 0; i < divs.length; i++) {
    div = document.createElement('div')
    document.body.appendChild(div)
}
//以上代码,第一次取得所有div 元素的HTMLCollection,下次取得会更新,造成死循环

//正确使用

var divs = document.getElementsByTagName('div'),
    i, len, div;
for (i = 0, len = divs.length; i < len; i++) {
    div = document.createElement('div')
    document.body.appendChild(div)
}

<hr />

DOM元素的特性(Attribute)  和    属性(Property)

Attribute特性: dom节点自带的属性,例如html中常用的id、class、title、align等:

//赋值:之后立即体现到DOM ,如果是标准特性,也会关联到相对应的属性值 ;

div1.setAttribute('class', 'a');
div1.setAttribute('title1', 'c');
Property属性: 而Property是这个DOM元素作为对象,其附加的内容,例如childNodes、firstChild等:

//取值,用.
var id = div1.id;
var attrs = div1.attributes;

//上面代码中的div1.attributes是取的attributes这一属性,取出来保存到attrs变量中,attrs就成了一个NamedNodeList类型的对象,里面存储了若干个Attr类型。

//赋值 :对属性Property可以赋任何类型的值,而对特性Attribute只能赋值字符串!
div1.className = 'a';



<hr >
NodeList v.s. HTMLCollection

Node及对应集合NodeList
Element(继承Node)及对应集合HTMLCollection
Document(继承Node)

































零js基礎 | 程序設計 | 9 - 客户端检测

直接把函数作为属性访问会导致JavaScript 错误。使用typeof 操作符会更靠谱一点,但IE
对typeof xhr.open 会返回"unknown",在浏览器环境下测试任何对象的某个特性是否
存在,要使用下面这个函数。

function isHostMethod(object, property) {
    var t = typeof object[property];
    return t == 'function' ||
        (!!(t == 'object' && object[property])) ||
        t == 'unknown';
}

result = isHostMethod(xhr, "open"); //true
result = isHostMethod(xhr, "foo"); //false

能力检测,不是浏览器检测
检测某个或某几个特性并不能够确定浏览器。下面给出的这段代码(或与之差不多的代码)可以在
许多网站中看到,这种“浏览器检测”代码就是错误地依赖能力检测的典型示例。

//错误!还不够具体
var isFirefox = !!(navigator.vendor && navigator.vendorSub);
//错误!假设过头了
var isIE = !!(document.all && document.uniqueID);

一次性检测

//确定浏览器是否支持Netscape 风格的插件
var hasNSPlugins = !!(navigator.plugins && navigator.plugins.length);
//确定浏览器是否具有DOM1 级规定的能力
var hasDOM1 = !!(document.getElementById && document.

在实际开发中,应该将能力检测作为确定下一步解决方案的依据,而不是用它来 判断用户使用的是什么浏览器。

完整用户代理字条串检测脚本代码

       var client = function() {
            //呈现引擎
            var engine = {
                ie: 0,
                gecko: 0,
                webkit: 0,
                khtml: 0,
                opera: 0,
                //完整的版本号
                ver: null
            };
            //浏览器
            var browser = {
                //主要浏览器
                ie: 0,
                firefox: 0,
                safari: 0,
                konq: 0,
                opera: 0,
                chrome: 0,
                //具体的版本号
                ver: null
            };
            //平台、设备和操作系统
            var system = {
                win: false,
                mac: false,
                x11: false,
                //移动设备
                iphone: false,
                ipod: false,
                ipad: false,
                ios: false,
                android: false,
                nokiaN: false,
                winMobile: false,
                //游戏系统
                wii: false,
                ps: false
            };
            //检测呈现引擎和浏览器
            var ua = navigator.userAgent;
            if (window.opera) {
                engine.ver = browser.ver = window.opera.version();
                engine.opera = browser.opera = parseFloat(engine.ver);
            } else if (/AppleWebKit\/(\S+)/.test(ua)) {
                engine.ver = RegExp["$1"];
                engine.webkit = parseFloat(engine.ver);
                //确定是Chrome 还是Safari
                if (/Chrome\/(\S+)/.test(ua)) {
                    browser.ver = RegExp["$1"];
                    browser.chrome = parseFloat(browser.ver);
                } else if (/Version\/(\S+)/.test(ua)) {
                    browser.ver = RegExp["$1"];
                    browser.safari = parseFloat(browser.ver);
                } else {
                    //近似地确定版本号
                    var safariVersion = 1;
                    if (engine.webkit < 100) {
                        safariVersion = 1;
                    } else if (engine.webkit < 312) {
                        safariVersion = 1.2;
                    } else if (engine.webkit < 412) {
                        safariVersion = 1.3;
                    } else {
                        safariVersion = 2;
                    }
                    browser.safari = browser.ver = safariVersion;
                }
            } else if (/KHTML\/(\S+)/.test(ua) || /Konqueror\/([^;]+)/.test(ua)) {
                engine.ver = browser.ver = RegExp["$1"];
                engine.khtml = browser.konq = parseFloat(engine.ver);
            } else if (/rv:([^\)]+)\) Gecko\/\d{8}/.test(ua)) {
                engine.ver = RegExp["$1"];
                engine.gecko = parseFloat(engine.ver);
                //确定是不是Firefox
                if (/Firefox\/(\S+)/.test(ua)) {
                    browser.ver = RegExp["$1"];
                    browser.firefox = parseFloat(browser.ver);
                }
            } else if (/MSIE ([^;]+)/.test(ua)) {
                engine.ver = browser.ver = RegExp["$1"];
                engine.ie = browser.ie = parseFloat(engine.ver);
            }
            //检测浏览器
            browser.ie = engine.ie;
            browser.opera = engine.opera;
            //检测平台
            var p = navigator.platform;
            system.win = p.indexOf("Win") == 0;
            system.mac = p.indexOf("Mac") == 0;
            system.x11 = (p == "X11") || (p.indexOf("Linux") == 0);
            //检测Windows 操作系统
            if (system.win) {
                if (/Win(?:dows )?([^do]{2})\s?(\d+\.\d+)?/.test(ua)) {
                    if (RegExp["$1"] == "NT") {
                        switch (RegExp["$2"]) {
                            case "5.0":
                                system.win = "2000";
                                break;
                            case "5.1":
                                system.win = "XP";
                                break;
                            case "6.0":
                                system.win = "Vista";
                                break;
                            case "6.1":
                                system.win = "7";
                                break;
                            default:
                                system.win = "NT";
                                break;
                        }
                    } else if (RegExp["$1"] == "9x") {
                        system.win = "ME";
                    } else {
                        system.win = RegExp["$1"];
                    }
                }
            }
            system.iphone = ua.indexOf("iPhone") > -1;
            system.ipod = ua.indexOf("iPod") > -1;
            system.ipad = ua.indexOf("iPad") > -1;
            system.nokiaN = ua.indexOf("NokiaN") > -1;
            //windows mobile
            if (system.win == "CE") {
                system.winMobile = system.win;
            } else if (system.win == "Ph") {
                if (/Windows Phone OS (\d+.\d+)/.test(ua)) {;
                    system.win = "Phone";
                    system.winMobile = parseFloat(RegExp["$1"]);
                }
            }
            //检测iOS 版本
            if (system.mac && ua.indexOf("Mobile") > -1) {
                if (/CPU (?:iPhone )?OS (\d+_\d+)/.test(ua)) {
                    system.ios = parseFloat(RegExp.$1.replace("_", "."));
                } else {
                    system.ios = 2; //不能真正检测出来,所以只能猜测
                }
            }
            //检测Android 版本
            if (/Android (\d+\.\d+)/.test(ua)) {
                system.android = parseFloat(RegExp.$1);
            }
            //游戏系统
            system.wii = ua.indexOf("Wii") > -1;
            system.ps = /playstation/i.test(ua);
            //返回这些对象
            return {
                engine: engine,
                browser: browser,
                system: system
            };
        }()
        console.log(client.engine)
        console.log(client.browser)
        console.log(client.system)