BOM与DOM模块个人汇总

11,111 阅读9分钟

前言

本基础系列文章,笔者整理一下自己的前端知识点,整理一下个人所学习过的基础,本意是提高自己,同时分享出来,希望对你也有帮助。

本文适合0~3工作经验的同学汇总知识点

包含个人抒写,如有理解错误,或者遗漏的的重要知识点,希望指出。

该系列,本意是提高自己,同时分享出来,希望对你也有帮助。

前端的发展史中,我们逻辑语言,曾经一度以“js”(Javascript )称呼。后来,随着前端的发展以及单页面架构到来,前端的逻辑逐渐以“es”(ECMAScript)称呼。

那么,js跟es(或es6)之间,有什么关系呢?答案是:js = es + bom + dom。

我们的文本节点之类,包括nodeType,nodeList,childNodes都属于dom的范畴。 可能你会觉得nodeType,nodeList,childNodes等知识点,他并不是那么重要。日常工作中几乎没用到过。笔者就在学习vue源码,虚拟dom转换成html时候遇到一些问题,都是通过本文的要点去解决的,还是需要能深刻分析。

本文对曾经js的一部分,bom跟dom进行详细的总结。

概念

我们先来看看他们的概念:

DOM:文档对象模型(Document Object Model,简称DOM),描述了处理网页内容的方法和接口。最根本对象是document(window.document)。

BOM:浏览器对象模型(Browser Object Model),描述了与浏览器进行交互的方法和接口。由navigator、history、screen、location、window五个对象组成的,最根本对象是window。

字面意思相对好理解。如果还是对概念模棱两可,好吧,这就是我写汇总的意义,汇总成自己方便理解的语言,也许我的理解有利于你对知识点的加深。

DOM就是我们日常对Html所有文本节点,元素,属性等操作,访问,修改等,都在dom的范畴。 其中,我们日常用的HTML DOM,他包括HTML的标准对象模型,W3C 标准等规范。

而BOM,就是跟浏览器有关的相关是属性,如浏览器的窗口呀,浏览器的页面跳转等。

看到这里,入行不深的小伙伴,可能都觉得非常简单。其实不然,很有学问。我们继续往下看。

知识点

节点

首先我们谈谈节点。

HTML文档中的所有内容都是节点,比如body之间就是一个节点,div与/div之间也是一个节点,甚至注释也算是注释节点。 一般在最外层,所以html也称根节点。

那么可见一个常规页面的节点是非常多的,而且他们还各自有交互关系,比如子父节点,兄弟节点,那么WC3定义如何来访问,修改他们呢。下面列举常用方法:

  • getElementById() 返回带有指定 ID 的元素。

  • getElementsByTagName() 返回包含带有指定标签名称的所有元素的节点列表(集合/节点数组)。

  • getElementsByClassName() 返回包含带有指定类名的所有元素的节点列表。

  • appendChild() 把新的子节点添加到指定节点。

  • removeChild() 删除子节点。

  • replaceChild() 替换子节点。

  • insertBefore() 在指定的子节点前面插入新的子节点。

  • createAttribute() 创建属性节点。

  • createElement() 创建元素节点。

  • createTextNode() 创建文本节点。

  • getAttribute() 返回指定的属性值。

  • setAttribute() 把指定属性设置或修改为指定的值。

  • innerHTML - 节点(元素)的文本值

  • parentNode - 节点(元素)的父节点

  • childNodes - 节点(元素)的子节点

  • attributes - 节点(元素)的属性节点

这是关于最简单的访问或者修改的方法。

那么节点本身包含了什么呢

这里包含三个内容。nodeType、nodeName、nodeValue。

首先,nodeType,是属性返回节点的类型。nodeType 是只读的。我们列举一下文本的类型。

元素类型NodeType
元素1
属性2
文本3
注释8
文档9

需要普及一下,这里每个节点都有一个childNodes属性,里边是一个NodeList对象(类数组),它是基于DOM结构动态执行查询的结果,因此 DOM 结构的变化能够自动反映在NodeList对象中。

同样每个节点还有一个children的属性,它与childNodes的区别就是,childNodes存储的是NodeList对象,而children返回的是HTMLCollection对象。NodeList存储的不只是元素节点,也有文本节点、注释节点等等,而HTMLCollection存储的只有元素节点。

我们通过案例来分析:

<div id="test">
    hello <span>word</span>
</div>

<script>
    let btn = document.getElementById("test");
    console.log(btn.childNodes, btn.children)
    //NodeList(3) [text, span, text]
    //HTMLCollection(1) [span]
</script>

还有一点需要普及的是,无论是children还是childNodes,他都不是真正意义的数组(关于数组,笔者ES6的总结array中已经详细介绍过,本文不再详写),是个类数组。

如果需要转换成数组,我们只能把获取到的NodeList或者HTMLCollection手动转换成数组。

我们NodeList还是HTMLCollection都不是数组,如果我们需要转化为数组,我们可以使用扩展运算符来操作:

const array = [...NodeList]
const array2 = [...HTMLCollection]

介绍到这里,你能想象一下vue的虚拟dom是怎么操作的吗?简单的来说,他就是利用object对象去模拟NodeList。

属性

属性名nodeName

属性名并不只是存在与属性节点,任何节点都有属性名。nodeName 属性规定节点的名称。他们的属性名如下:

  • 元素节点的 nodeName 与标签名相同
  • 属性节点的 nodeName 与属性名相同
  • 文本节点的 nodeName 始终是 #text
  • 文档节点的 nodeName 始终是 #document

属性值nodeValue

nodeValue 属性规定节点的值,也就是每个属性名,就有会他对应的属性值。

  • 元素节点的 nodeValue 是 undefined 或 null
  • 文本节点的 nodeValue 是文本本身
  • 属性节点的 nodeValue 是属性值

属性节点

我们再来看一下属性节点。什么是属性?我们元素中的内置对象,就是属性节点。比如style,class, id,都称为元素的属性节点。

  • Element.getAttributeNames();//获取属性名
  • Element.getAttribute("class");//获取class的属性值
  • Element.attributes.item(0);//获取元素第一个属性键值对
  • Element.hasAttribute("class");//判断是否有class属性
  • Element.setAttribute("class", "active");//设置class属性

比如我们需要重置元素class的值,我们就可以通过setAttribute重新给class赋值。 当然还有一个内置class对象可以操作:Element.classList.add("active", "show")

介绍到这里,你能想象一下vue的的v-if或者v-on是怎么实现的吗?简单的来说,他就是把他当成一个元素属性,获取到对应的标识,再去解析。

事件

再普及一下dom的事件,我们日常用到的点击,鼠标等事件,就是dom事件。onclick,onchange,onmousedown, onmouseup,onfocus等等,他都是一个dom事件。

这里需要给大家普及一下关于dom事件的一些冷知识点或者细节:

  1. js如果定制了onclick事件,会直接覆盖掉原来标签的onclick事件。如下边栗子,test就失效了。

     <div id="btn" onclick="test(this)"> 按钮 </div>
    
     let btn = document.getElementById("btn");
     btn.onclick = function (e) {
     	 alert("2");
     }
     	
     function test(){
     	alert("1");
     }
     
    

2.onclick的触发来自监听本身,而监听事件addEventListener还需要检测事件的回流,所以优先级永远都是:onclick>addEventListener, 如下边栗子:

<div id="btn" onclick="test(this)"> 按钮 </div>
	<script>
		let btn = document.getElementById("btn");
		btn.onclick = function (e) {
			alert("1");
		}

		btn.addEventListener("click", function (e) {
			alert("2");
		})
		
	</script>
	

执行1再执行2.

3.获取的对象中,currentTarget表示当前对象,而target表示事件的对象。 如下边栗子:

按钮0
按钮1
let btn_box = document.getElementById("btn_box");

btn_box.addEventListener("click", function (e) {
	consloe.log( e.currentTarget);
	consloe.log( e.target);
})

点击按钮0, currentTarget对象指的是btn_click_0,而target对象是btn_box

自定义事件

除了官方自带的click,focus等事件可以监听之外,我们还可以自定义事件进行监听。举个栗子:

// createEvent创建事件
let myEvent = document.createEvent('Event');
// 定义事件名为'build'.
myEvent.initEvent('', true, true);
//eventType:事件名称
//canBubble:是否支持冒泡
//cancelable:是否可以用 preventDefault() 方法取消事件。
new3Event.name = "document.createEvent创建的自定义事件"
// 如果需要监听事件
document.addEventListener('myEventName', function (e) {
    // e.target matches elem
    alert(e.name)
}, false);

// 触发对象可以是任何元素或其他事件目标
document.dispatchEvent(myEvent);

这是最简单的创建”自定义事件“的方法,document.createEvent。

如果你还需要自定义传参数的话,可以使用CustomEvent或者Event.这里不做详细介绍。

看完上边的demo,我们貌似知道了大概的用法。但是他的带来的好处是什么?

自定义事件的优缺点

优缺点有点类似传统的监听事件。其优点就是,各模块之间低耦合,互不影响。

缺点的话,不好定位问题,容易导致诡秘的错误。大项目出错时,连入口都很难定位在哪里。

BOM

接下来谈谈bom的知识点。

bom的知识点,相对的话只是知识面的了解。因为属于应用开发范畴(浏览器开发),我们只需要对他的知识面有所了解,建议不深入。

该部分,如有面试或者日常也不会挖深,只考虑是否了解知识点

他可以由下边6部分组成:

Location

下边为Location的属性

属性描述栗子
hash获取锚点,简单来说就是url的#后边#detail?a=1
hosturl的端口 + 端口www.baidu.com:8080
hostname主机路径www.baidu.com
href完整urlwww.baidu.com?a=1
pathname返回当前 URL 的路径部分/index.html
port端口8080
protocol协议http或htttps
search协议获取参数,简单来说就是url的?后边a=1&b2

下边为Location的方法

方法描述
assign加载新的文档
reload重新刷新页面
replace用新的文档替换当前文档

Navigator

属性说明
appCodeName返回浏览器的代码名
appName返回浏览器的名称
appVersion返回浏览器的平台和版本信息
cookieEnabled返回指明浏览器中是否启用 cookie 的布尔值
platform返回运行浏览器的操作系统平台
userAgent返回由客户机发送服务器的user-agent 头部的值

Screen

属性说明
availHeight返回屏幕的高度(不包括Windows任务栏)
availWidth返回屏幕的宽度(不包括Windows任务栏)
colorDepth返回目标设备或缓冲器上的调色板的比特深度
height返回屏幕的总高度
pixelDepth返回屏幕的颜色分辨率(每象素的位数)
width返回屏幕的总宽度

History

属性说明
back返回上一页
forward返回下一页
go加载 history 列表中的某个具体页面

结语

该文章除了api文档参考第三方,其他均为原创。 如有理解错误,或者遗漏的的重要知识点,希望指出。 如对你有少许帮助,请点赞与关注,后续即将持续更新文章。、