DOM 基础总结

2018-08-12  本文已影响2人  千反田爱瑠爱好者

DOM(Document Object Model),最初是为XML设计。

节点属性

HTML标签成树形结构,在内存中以文档对象映射的形式存放:

<!DOCTYPE html>
<html land='zh-Hans'>
    <head>
        <meta>
        <title>
    </head>
    <body>
    </body>
</html>

DOM API

一般是以下单词相互组合:

child / children / parent
node
first / last
next / previous
sibling / siblings
type
value / text / content
inner / outer
element

例如:

childNodes           // 获取子节点包括标签和回车键(文本)
children             // 获取子标签
firstElementChild    // 第一个元素儿子
previousSibling      // 上一个兄弟节点
previousElementSibling    // 上一个元素兄弟节点
nodeName            // body节点名称(注意除了svg是小写以外别的标签都是大写)
nodeType            // 节点类型编号
textContent         // 获取元素的文本内容(包括<script>、<style>等)
innerHTML           // 修改HTML标签(不安全,比如用户注入<script>)
innerText           // 获取元素文本内容(不包括<script>、<style>等,不包括display:none的,由于受CSS影响,会触发重排:如通过innerText修改节点属性导子节点丢失)
'textContent' in document.head ? document.body.textContent: document.body.innerText
...

关于DOM API,学习DocumentFragment优化

节点方法

如果一个属性是函数,那么这个属性也叫做方法(即函数属性),常用方法:

appendChild()      // 添加子节点
cloneNode()        // 克隆节点,默认是浅拷贝(true为深拷贝)
contains()         // 是否包含系欸但
hasChildNodes()    // 是否有子节点
insertBefore()     // 在前面插入节点
isEqualNode()      // 是否相等节点(元素完全一样)
isSameNode()       // 是否相同节点,等价于“===”
removeChild()      // 移除子节点(在内存中,不出现在页面)
replaceChild()     // 替换子节点
normalize()        // 常规化(如合并两个孩子的文本内容)
...

Document API

属性

body
characterSet
childElementCount
children
doctype
documentElement
domain
fullscreen
head
hidden
images
links
location
onxxxxxxxxx        // 事件监听
origin
plugins
readyState
referrer
scripts
scrollingElement
styleSheets
title
visibilityState

方法

close
createDocumentFragment
createElement
createTextNode
execCommand          // 执行交互命令(开发富文本编辑器)
exitFullscreen
getElementById
getElementsByClassName
getElementsByName
getElementsByTagName
getSelection
hasFocus
open
querySelector        // 选择器(jQuery)
querySelectorAll     // 选择器,返回伪数组(instance of Array)
registerElement
write
writeln

其中document.close在异步操作中很危险:

<script>
    document.write(1)
    document.write(2)
    setTimeout(() ={document.write(3)}, 1000)    
// 写入1、2后document已执行close
// 1s后重新执行open,write会覆盖之前写入的内容
</script>

Element API

...

事件模型

绑定事件的方式

<button id=X, onclick='print()'>A</button>
<!-- 或 -->
<button id=X, onclick='print.call()'>A</button>
<!-- onclick后面跟的是要执行的代码,不是js函数 -->

<script>
    X.onclick = print    // 指定函数(不是调用)
</script>

事件监听队列

<script>
   // 第二次定义onclick,会把第一次覆盖
    xxx.onclick = function({    
        concole.log('1')
    })
    xxx.onclick = function({    
        concole.log('2')
    })

    // 队列会按事件设置的顺序执行
    f1 = function(){      
        concole.log('ok')
        // xxx.removeEventListener('click', f1)    // 执行一次即从队列中移除,只能执行一次
    }
    xxx.addEventListener('click', f1)
</script>

事件捕获和冒泡

<div>
    <div id='grand'>
        <div id='parent'>
            <div id='son'>
            </div>
        </div>
    </div>
</div>

<script>
    grand.addEventListener('click', function f1(){
        console.log('grand')
    })
    parent.addEventListener('click', function f2(){
        console.log('parent')
    })
    son.addEventListener('click', function f3(){
        console.log('son')
    })
    // 1、点击son所在区域,parent和grand都会触发事件
    // 2、事件执行顺序默认为fn3,fn2,fn1(addEventListener的第三个参数默认为false,称为冒泡;设置true则逆序执行,称为捕获)
    // 3、如果同一个元素上既定义了捕获也定义了冒泡,则按定义的顺序执行(不会覆盖)
</script>

点击别处关闭浮层

html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        body{border: 1px solid red;}
        .wrapper{position: relative;display: inline-block;}
        .popover{border: 1px solid red;position: absolute;left: 100%;top: 0;white-space: nowrap;padding: 10px;margin-left: 10px;background: white;display: none;}
        .popover::before{position: absolute; right: 100%;top: 5px;border: 10px solid transparent;border-right-color: red;content: '';}
        .popover::after{position: absolute; right: 100%; top: 5px; border: 10px solid transparent; border-right-color: white; content: ''; margin-right: -1px;}
    </style>
</head>
<body>
<div id="wrapper" class="wrapper">
    <button id="clickMe">点我</button>
    <div id="popover" class="popover">
        <input type="checkbox">浮层
    </div>
</div>
</body>
</html>

方法1:

<script>
    clickMe.addEventListener('click', function(e){
        console.log('show')
        popover.style.display = 'block'     // 点击按钮出现浮层
    })

    wrapper.addEventListener('click', function(e){
        // 点击出现浮层的按钮时时事件会冒泡,最后触发了document的隐藏事件
        // 需要在中间层添加停止传播,则事件会在外层div被阻隔
        e.stopPropagation()
    })

    document.addEventListener('click', function(){
        console.log('none')
        popover.style.display = 'none'      // 点击最外面隐藏浮层(注意不能设置body,body的高度取决于布局,没有元素的区域不生效)
    })
</script>

方法2(使用jQuery):

<script>
    $(clickMe).on('click', function() {
        $(popover).show()
        // 点击的时候这个事件会马上被加到处理队列中,这个过程优先于冒泡阶段
        // 顺序:内层点击事件触发 -> 定义外层点击事件 -> 冒泡到外层 -> 外层点击事件触发
        // $(document).one('click', function() {
        //     $(popover).hide()
        // })
        setTimeout(function() {
            $(document).one('click', function() {
                $(popover).hide()
            })
        }, 0)       // 此处定义的document点击事件会在冒泡阶段结束后才生效
    })
</script>

图解事件捕获和冒泡:


<html>
<head>
    <script src="//code.jquery.com/jquery-2.1.1.min.js"></script>
    <meta charset="utf-8">
    <title></title>

    <style>
        *{margin:0;padding:0;box-sizing:border-box;}
        .red.active {background: red;}
        .blue.active {background: blue;}
        .green.active {background: green;}
        .yellow.active {background: yellow;}
        .orange.active {background: orange;}
        .purple.active {background: purple;}
        div {border: 1px solid black;padding: 20px;transition: all 0.5s;display: flex; flex: 1;border-radius: 50%;background: white;}
        .red{width: 500px;height: 500px;}
    </style>
</head>
<body>
<div class="red">
    <div class="blue">
        <div class="green">
            <div class="yellow">
                <div class="orange">
                    <div class="purple">

                    </div>
                </div>
            </div>
        </div>
    </div>
</div>
<script>
    let divs = $('div').get()
    let n = 0
    for (let i = 0; i < divs.length; i++) {
        divs[i].addEventListener('click', () => {
            setTimeout(() => {
                divs[i].classList.add('active')
            }, n * 500)     // 点击0.5s后添加active
            n += 1
        }, true)        // 设置为true,表示从外层到内层,事件捕获
    }
    
    for (let i = 0; i < divs.length; i++) {
        divs[i].addEventListener('click', () => {
            setTimeout(() => {
                divs[i].classList.remove('active')
            }, n * 500)
            n += 1
        })
    }
</script>
</body>
</html>
上一篇 下一篇

猜你喜欢

热点阅读