DOM 基础总结

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

节点属性

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

<!DOCTYPE html>
<html land='zh-Hans'>
    <head>
        <meta>
        <title>
    </head>
    <body>
    </body>
</html>
  • Node:Element(元素),Text(文本),Document(html标签,html是document的子节点),Comment(注释);
  • 页面中的节点通过上面的构造函数创建出对象,提供一系列操作节点的API(DOM API)
  • 其中Node也是派生自Object。

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>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342

推荐阅读更多精彩内容