前言
ECMAScript,描述了该语言的语法和基本对象,如类型、运算、流程控制、面向对象、异常等。
文档对象模型(DOM),描述处理网页内容的方法和接口。
浏览器对象模型(BOM),描述与浏览器进行交互的方法和接口。
DOM/BOM架构
概述
JavaScript运行在浏览器
BOM就是连接JavaScript代码和浏览器的桥梁,而DOM就是用来操作各种标签元素的。
- BOM包括 window、history、location、document ...
-
DOM包括 Document(整个文档)、Element(标签元素)、CharacterData(字符数据)、Attr(属性),这些元素又可以继续往下划分。
Document 又可以分为HTMLDocument(就是我们定义的html文件)和XMLDocument(XML文件,安卓会用,前端用不到)
Element 可以划分为 HTMLElement(表示 HTML 中的一个元素,比如div),HTMLElement又可以划分为HTMLDIvElement 和 HTMLImageElement 故名思义
CharacterData 可以划分为text(text标签)和Comment(注释)
Attr 可以理解我们元素的class属性id属性以及值
继承关系
- 其中DOM元素、window对象都继承自EventTarget,所以它们都有EventTarget上的实例方法而document是HTMLDocument的实例对象
- 所以window上是可以绑定事件,监听事件,分发事件的
- 其中DOM 中的所有元素节点都继承自EventTarget接口,所以DOM中任意节点可以绑定事件,监听事件,分发事件
我们可以在浏览器中打印它的原型属性
通过下图我们可以看出,window继承Window,Window继承自EventTarget
通过下图我们可以看出,document继承HtmlDocument,HtmlDocument继承自Document,Document继承自Node节点,Node节点继承自EventTarget
顺便说一句:EventTarget继承自Object,Object继承自null
EventTarget 接口
EventTarget 是一个 DOM 接口,由可以接收事件、并且可以创建侦听器的对象实现。
Element,document 和 window 是最常见的 event targets
EventTarget有三个原型方法,在window和DOM元素上都可以使用
addEventListener 给元素绑定事件
removeEventListener 移除元素绑定的事件
dispatchEvent 派发事件
BOM
认识BOM
- JavaScript有一个非常重要的运行环境就是浏览器,而且浏览器本身又作为一个应用程序需要对其本身进行操作,所以通常浏览器会有对 应的对象模型(BOM,Browser Object Model)。
-
BOM主要包括一下的对象模型:
window:包括全局属性、方法,控制浏览器窗口相关的属性、方法;
location:浏览器连接到的对象的位置(URL);
history:操作浏览器的历史;
document:当前窗口操作文档的对象;
-
window对象在浏览器中有两个身份:
身份一:全局对象。我们知道ECMAScript其实是有一个全局对象的,这个全局对象在Node中是global;在浏览器中就是window对象;
身份二:浏览器窗口对象。作为浏览器窗口时,提供了对浏览器操作的相关的API;
Window全局对象
在浏览器中,window对象就是之前经常提到的全局对象
- 比如在全局通过var声明的变量,会被添加到全局环境变量中,也就是会被添加到window上;
- 比如window默认给我们提供了全局的函数和类:setTimeout、Math、Date、Object等;
var message = 'hello'
function foo(){
console.log("foo")
}
console.log(window.message)
window.foo()
window.setTimeout(()=>{
console.log('setTimout')
})
const obj = new window.Object()
console.log(obj)
Window窗口对象
window是一个复杂的大对象,包含了大量的对象和方法
第一:包含大量的属性,localStorage、console、location、history、screenX、scrollX等等(大概60+个属性);
第二:包含大量的方法,alert、close、scrollTo、open等等(大概40+个方法);
第三:包含大量的事件,focus、blur、load、hashchange等等(大概30+个事件);
第四:包含从EventTarget继承过来的方法,addEventListener、removeEventListener、dispatchEvent方法;
参考地址:MDN文档:developer.mozilla.org/zh-CN/docs/…
[图片上传失败...(image-bb8cd9-1676958099638)]
常见的属性
// screenX和screenY属性返回窗口相对于屏幕的X和Y坐标。
console.log(window.screenX)
console.log(window.screenY)
// 监听滚动
window.addEventListener("scroll", () => {
console.log(window.scrollX, window.scrollY)
})
// 获取窗口的宽度与高度:
console.log(window.outerHeight)
console.log(window.innerHeight)
常见的方法
const scrollBtn = document.querySelector("#scroll")
scrollBtn.onclick = function() {
//1.scrollTo
window.scrollTo({ top: 2000 })
//2.close
window.close()
// 3.open
window.open("http://www.baidu.com", "_self")
}
常见的事件
// 整个页面以及所有资源加载完成
window.onload = function() {
console.log("window窗口加载完毕~")
}
window.onfocus = function() {
console.log("window窗口获取焦点~")
}
window.onblur = function() {
console.log("window窗口失去焦点~")
}
//hash 改变
const hashChangeBtn = document.querySelector("#hashchange")
hashChangeBtn.onclick = function() {
location.hash = "aaaa"
}
window.onhashchange = function() {
console.log("hash发生了改变")
}
Navigator 对象
Navigator 对象包含有关浏览器的信息。到底提供哪些信息很大程度取决于用户的浏览器,但是也有一些公共的属性,如userAgent 存在所有的浏览器中
Navigator 对象常见的属性
window.navigator.appCodeName
//返回浏览器的代码名 'Mozilla'
window.navigator.appName
//返回浏览器的名称 'Netscape'
window.navigator.appVersion
//返回浏览器的平台和版本信息
//'5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1'
window.navigator.cookieEnabled
//返回指明浏览器中是否启用 cookie 的布尔值 true
window.navigator.platform
//返回运行浏览器的操作系统平台 'MacIntel'
window.navigator.userAgent
//返回由客户机发送服务器的user-agent 头部的值
//'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.64 Safari/537.36'
使用场景
检测插件
可以检测浏览器内是否安装了特定的插件
navigator.plugins
判断系统类型,版本信息
location对象
location 对象 是最有用的BOM对象之一
它既是window对象的属性,也是document对象的属性,window.location 和document.location引用的是同一个对象。
常见属性
- href: 当前window对应的超链接URL, 整个URL;
- protocol: 当前的协议;
- host: 主机地址;
- hostname: 主机地址(不带端口);
- port: 端口;
- pathname: 路径;
- search: 查询字符串;
- hash: 哈希值;
- username:URL中的username(很多浏览器已经禁用);
- password:URL中的password(很多浏览器已经禁用);
常用方法
- assign:赋值一个新的URL,并且跳转到该URL中;
- replace:打开一个新的URL,并且跳转到该URL中(不同的是不会在浏览记录中留下之前的记录);
- reload:重新加载页面,可以传入一个Boolean类型;如果把该方法的参数设置为 true,那么无论文档的最后修改日期是什么,它都会绕过缓存,从服务器上重新下载该文档。
location.assign("http://www.baidu.com")
location.href = "http://www.baidu.com"
location.replace("http://www.baidu.com")
location.reload(false)
Screen对象
在编程中使用不多,只用来表明客户端的能力,其中包括浏览器窗口外部的显示器的信息,如像素的宽度和高度,每个浏览器的screen对象都包含着不同的属性。根据具体业务场景去查询就好。
history 对象
history对象允许我们访问浏览器曾经的会话历史记录。
history对象有两个属性
- length:会话中的记录条数;
- state:当前保留的状态值;
history对象有五个方法:
- back():返回上一页,等价于history.go(-1);
- forward():前进下一页,等价于history.go(1);
- go():加载历史中的某一页;
- pushState():打开一个指定的地址;
- replaceState():打开一个新的地址,并且使用replace;
总结
BOM 以window对象为依托,表示浏览器窗口以及页面可见区域
DOM
document Object Model 文档对象模型
节点层次
DOM可以把任何HTML和XML文档描绘成一个由多层节点构成的树形结构。
<html>
<head>
<meta charset="UTF-8">
<title>测试</title>
</head>
<body>
<h1>标题</h1>
<ul>
<1i>
<a href="#">链接</a>
</1i>
</ul>
</body>
</html>
上图中就包括DOM的主要节点
Document文档节点
表示整个 HTML 页面(相当于 document 对象)
当需要访问任何标签、属性或文本时,都可以通过文档节点进行导航
Element元素节点 ul h1 li
表示 HTML 页面中的标签(即 HTML 页面的结构)
当访问 DOM 树时,需要从查找元素节点开始
Attr 属性节点 href
表示 HTML 页面中的开始标签包含的属性
Text 文本节点 比如title的内容
Node 类型
所有的DOM节点类型都继承自Node接口,每个节点都有一个nodeType属性,用于表明节点的类型。
对于HTML文档,节点主要有以下六种类型:Document节点、DocumentType节点、Element节点、Attribute节点、Text节点和DocumentFragment节点。
分类
节点 | 名称 | 含义 |
---|---|---|
Document | 文档节点 | 整个文档(window.document) |
DocumentType | 文档类型节点 | 文档的类型(比如 'DOCTYPE html') |
Element | 元素节点 | HTML元素(比如body、a等) |
Attribute | 属性节点 | HTML元素的属性(比如class="right") |
Text | 文本节点 | HTML文档中出现的文本 |
DocumentFragment | 文档碎片节点 | 文档的片段 |
常用属性
Node 有几个非常用且重要的属性
- nodeName:node节点的名称;
- nodeType:可以区分节点的类型;
- nodeValue:node节点的值;
- childNodes:所有的子节点;
Document 类型
JavaScript 通过Document 类型表示整个文档。
Document 类型可以表示 HTML 页面或者 其他基于 XML 的文档。不过最常用的应用还是作为HTMLDocument实例的document 对象。
在浏览器中 document 对象是 HTMLDocument的一个实例,表示整个HTML页面。而且,document对象也是window对象的一个属性,因此可以作为全局对象来访问。
常见属性
- document.body 返回文档的body元素
- document.title 返回当前文档的标题
- document.head 返回当前文档的head内容
- document.children[0] 返回当前文档html内容
常见方法
- 创建元素
- 获取标签元素
// 创建元素
const imageEl = document.createElement("img")
const imageEl2 = new HTMLImageElement()
// 获取元素
const divEl1 = document.getElementById("box")
const divEl2 = document.getElementsByTagName("div")
const divEl3 = document.getElementsByName("title")
- 文档写入
将输出流写入到网页的能力。
document.write()
document.writeln()
document.open()
document.close()
Element 类型
Element 类型用于表现XML和HTML元素,提供了对元素标签名,子节点及特性的访问
我们平时创建的div、p、span等元素在DOM中表示为Element元素
常见属性
- 子元素 children childNodes
- tagName
- id/class
- clientWidth/clientHeight
- clientLeft/clientTop
- offsetLeft/offsetTop
常见方法
获取特性 getAttribute 修改某个特性 setAttribute
创建元素 document.createElement()
Text 类型
文本节点由Text类型表示,包含的是可以照字面解释的纯文本内容
- 创建文本节点:document.createTextNode()
Comment 类型
注释
DocumentFragment 类型
DOM规定文档片段是一种轻量级的文档,不会像完整的文档那样占有额外的资源
可以在里面保存将来会添加到文档的节点。要创建文档片段,可以使用document.createDocumentFragment()
文档片段本身永远不会成为文档树的一部分
Attr类型
元素的特性在DOM中用Attr类型来表示。很少使用。
总结
DOM1级将HTML和XML文档看作一个层次化的节点树,方便js来直接操作。
DOM 是由各种节点构成的
- 最基本节点是Node,所有的节点都继承自Node
- Document 表示整个文档
- Element 表示文档中的HTML 或者XML 元素
DOM扩展
对DOM的扩展主要包括 选择符API 和 HTML5
选择符API
选择符,最核心的两个API 就是 querySelector() 和 querySelectorAll()
可以通过Document 和 Element 类型的实例调用
const divEl1 = document.querySelector(".content")
const divEl2 = document.querySelectorAll(".content")
HTML5
html5涉及的面非常广,我们这里这讨论与DOM 节点相关的内容
获取dom元素
- getElementsByClassName() 可以通过document 对象和所有HTML元素调用该方法,查询一个或者包含类名的字符串
自定义数据属性
可以为元素添加非标准的属性,但是要添加前缀 data-
通过元素的 dataset 属性来访问自定义的属性的值
<div id ="myDiv" data-appId = "12345" data-name="yz"></div>
var div = document.getElementById('myDiv')
var appId = div.dataset.appId
var name = div.dataset.name
插入标记
innerHTML属性
- 可以获取调用元素的所有子节点对应的html片段
- 可以是根据指定的值创建DOM树,替换原有的元素节点
一般我们插入大量新HTML标记时,使用innerHTML 与通过多次DOM操作先创建节点再指定它们之间的关系相比,效率更高,因为在设置innerHTML 时就会先创建一个HTML解析器,这个解析是在浏览器级别的基础上代码(c++)运行的,因此比执行js 快得多,当然也会带来 创建销毁 html 解析器也有性能消耗。所以控制次数。
DOM2和DOM3
DOM1级主要定义的是HTML和XML文档的底层结构
DOM2级和DOM3级是在这个结构基础上引入了更多的交互能力和特性。扩展了DOM API,以满足操作DOM的所有需求,同时提供更好的错误处理和特性监测能力
DOM变化
- Node 类型 Document 类型 Element 类型 增加了命名空间的概念
- DOM3引入 两个辅助比较节点的方法 isSameNode() 和 isEqualNode( )
- 一个判断相同 两个节点引用的是同一个对象
- 一个判断相等 两个节点是同类型的对象,具有相等的属性(nodeName,nodeValue等等),而且他们的attributes和 childNodes属性也相等(相同位置包含相同的)
var div1 = document.createElement("div")
div1.setAttribute("class","box")
var div1 = document.createElement("div")
div1.setAttribute("class","box")
alert(div1.isSameNode(div1)) // true
alert(div1.isEqualNode(div1)) // true
alert(div1.isSameNode(div2)) // false
- iframe中的文档对象可以通过contentDocument 访问 所有浏览器都支持
var iframe = document.getElementById("myIframe")
var iframe = iframe.contentDocuemnt || iframe.contentWindow.document
样式变化
访问元素的样式
- 新增style属性 可以通过style对象访问所有样式信息,也可以进行修改
- document.default.getComputedStyle(dom) 可以返回整个dom的样式
操作样式表
- 大多数情况下,使用style属性就可以满足所有操作样式柜子的需求
元素大小
- 偏移量
- offsetHeight offsetWdith offsetLeft offsetTop
- 可以通过以上四个属性计算
- 客户区大小
- clientHeight clientWidth
- 滚动大小
- scrollHeight scrollWidth scrollLeft scrollTop
- scrollLeft scrollTop可以用来确定当前元素滚动状态
-
确定元素大小
- getBoundClientRect()返回一个矩形对象,包含四个属性 left top right bottom,给出了元素在页面中相对于视口的位置。
- top/y:元素上边到视窗上边的距离;
- right:元素右边到视窗左边的距离;
- bottom:元素下边到视窗上边的距离;
- left/x:元素左边到视窗左边的距离;
- width:元素的宽度;
- height:元素的高度;
范围
为了让开发人员更方便得控制页面,dom2 定义了范围 range接口。
document.createRange()
- 用dom范围实现简单选择
var range1 = document.createRange()
var p1 = document.getElementById('p1')
range1.selcetNode(p1)
- 也可以操作修改dom范围中的内容
小结
dom2 级主要新增了操作样式的能力和操作范围内dom的能力
总结
对于dom和bom的学习,我所秉持的观点依然是,抓大放小,建立知识体系,常用的api可以了解,不常用的api知道去哪里查就好,因为平常业务开发也接触不到太底层的代码。
框架发展到今天,对我们前端开发来说,已经很少去操作Dom了,但框架已经帮助我们做了,对于Bom的交互也有很多封装成熟的函数库,但是如果要对前端深入学习,我觉得这些知识还是必须掌握的,前端学习js 永远是基础,框架函数库,都是锦上添花的东西。
我们要知其然,更要知其所以然。