浏览器对象模型(Browser Object Model) / BOM
BOM是由一系列相关对象构成,每个对象都提供了很多方法和属性。
在 BOM 里最重要的对象有 5 个, 分别如下:
- window (窗口):window 是整个网页的框架,每个网页的内容都是装载在 window 里面
- navigator (浏览器):navigator 里面存储浏览器相关信息
- history (历史):我们知道每个网页可以前进后退,history 便拿来存储整个网页栈的
- screen (显示屏幕):screen 包含我们显示屏幕的信息,这个是硬件信息
- location (地址):location 包含当前访问的地址(网址)信息
- screen 是 整个电脑 唯一的
- navigator 是 整个浏览器 唯一的,如果有多个浏览器就会有多个 navigator
- window 是 每个网页 唯一的,每个网页都有一个独立的 window
- history,location 是 每个网页 的信息,当然也是网页唯一的
HTML 中嵌入 Javascript
window
- window 对象表示一个浏览器窗口或一个 frame 框架,它处于对象层次的最顶端,它提供了处理浏览器窗口的方法和属性。
- window 对象是浏览器对象中的默认对象,所以可以隐式地引用 window 对象的属性和方法。在浏览器环境中,添加到 window 对象中的方法、属性等,其作用域都是全局的。
Location/History
location其用来保存当前网页位置的信息。
Location 方法
--- reload() 方法
为了防止无限快速循环,我们设置一个定时器延迟调用 reload。
location.reload()
方法用来刷新当前页面,就像刷新按钮一样。
setTimeout(function () {
window.location.reload();
}, 3000);
跳转到新的地址
直接将网页地址赋值给 Location
可以直接修改location的值。
window.location = 'https://www.youkeda.com';
History
History 允许操作浏览器的曾经在标签页或者框架里访问的会话历史记录,由这个名称我们得知,History 会存储该窗口的历史记录。
在实际存储中用到的数据结构和数组特别类似,叫做栈。
History中方法
back() 和 forward() ,分别对应到浏览器左上角的返回和前进按钮。
Navigator/Screen
Navigator 表示用户代理的状态和标识,也就是浏览器基本信息,在这里面我们需要了解一个属性 --- userAgent,代表当前浏览器的用户代理。
DOM
文档对象模型 (DOM) 可以将 web 页面 与 脚本或编程语言 连接起来.
重点
1. web 页面
这里的 web 页面,也就是之前我们用 HTML 和 CSS 绘制的页面,也称作为文档
2. 脚本或编程语言 为什么这里不直接说将 Web 页面和 Javascript 语言连接起来,而要绕一下说脚本或编程语言呢?
因为 DOM 是一种规范,或者是一种约定,只要遵循这个规范,那么无论是
Javascript
,还是python
,或者java
都可以被连接起来。
访问DOM
获取DOCUENT
web 网页最终会映射为一棵 DOM 树,DOM 树连接网页和 Javascript 语言。
DOCUMENT 元素会存在全局变量 window 下面,可以直接访问:
window.document;
选择器查询
选择器查询方法 --- querySelector()
//基础筛选条件
'.subtitle';
//加强版本,加上父亲筛选, 筛选 main标签下面 -> class为core的节点下面 -> class为subtitle的节点
'main .core .subtitle';
document.querySelector('main .core .subtitle');
迭代查询
当我们得到 subtitle 元素后,我们还可以利用这个元素,继续筛选器内部元素,比如我们想筛选器内部的 a 标签。
let subtitle = document.querySelector('main .core .subtitle');
console.log(subtitle.querySelector('a'));
选择器全量查询
查询上面 HTML 中的所有 input 节点.
document.querySelectorAll('input');
查询返回的是一个类数组,我们可以直接通过索引访问。
类数组,顾名思义类似数组形式,(可以通过索引访问的对象我们都可以称之为类数组),从 JSConsole 中我们实际得到的是NodeList对象。
getElementById(): 根据 id 查询某个节点
getElementsByClassName(): 根据 class 查询多个节点
getElementsByTagName(): 根据 标签名 查询多个节点
querySelector 查询出来的元素是拷贝的原始数据,不会再随着页面 DOM 节点的改变而变化 get 系列方法 查询出来的元素就是原始数据,所以会随着页面的 DOM 节点的改变而变化
DOM属性
DOM种类
<!-- HTMLDocument 根文档 -->
<html>
……
</html>
<!-- HTMLDivElement DIV类型 -->
<div class="subtitle">
……
</div>
<!-- HTMLAnchorElement 超链接类型 -->
<a class="free-bright">免费靓号</a>
<!-- HTMLInputElement Input类型 -->
<input class="password" type="pasworkd" placeholder="请输入密码" />
DOM的类别
- 元素节点
- 特性节点
- 文本节点
- …… 其他类别不重要。
- 整个 HTML 中,无论是标签,标签属性,还是纯文本字符串都是
Element
, 不同的地方在于nodeType
分别为1, 2, 3
。 - HTML 标签都是元素节点,可以用
nodeName
获取标签名称 - 纯文本都是文本节点,可以用
nodeValue
获取文本内容 - 标签的每个属性都是特性节点,可以用
nodeName
取得属性 Key,用nodeValue
取得属性 Value attributes
可以获取元素节点的所有属性,得到的结果是一个字典,通过属性 Key 获取对应的特性节点。
DOM内容
属性 | 总结 | |
---|---|---|
outerHTML | 整个 DOM 的 HTML 代码 | |
innerHTML | DOM 内部 HTML 代码 | |
innerText | DOM 内部纯文本内容 |
DOM亲属
let divDom = document.querySelector('div#test');
console.log(divDom.firstChild, divDom.lastChild);
console.log('-----');
console.log(divDom.childNodes);
console.log('-----');
console.log(divDom.parentNode);
属性 | 值 | 总结 |
---|---|---|
firstChild | 指定节点的第一个子节点 | |
lastChild | 指定节点的最后一个子节点 | |
childNodes | 指定节点的子节点的集合 | |
parentNode | 指定节点在 DOM 树中的父节点 |
lastChild 的值为 text
实际上就是换行符。
DOM样式
属性 | 类型 | 值 | 总结 |
---|---|---|---|
classList | DOMTokenList 类数组 | ['test'] | classList 数组方式存储所有的 class 名称 |
style | CSSStyleDeclaration | color 属性为rgb(255, 51, 0) | 对象或字典的方法存储 CSSStyle |
DOM数据属性
HTML 提供一种数据属性的标准,利用data-*
允许我们在标准内于 HTML 元素中存储额外的信息。
有一些数据,,不一定是直接展示的,有可能字数是某种特效才展示,分类数据是动态更新时需要用到,可以利用data-*
来存储。
<article data-parts="3" data-words="1314" data-category="python"></article>
数据的获取:
const article = document.querySelector('article');
console.log(article.dataset);
dataset
是个 Map 对象,它是data-*
这个*
的Key-Value集合。
DOM操作
1. 创建标签节点
document.createElement(tagName)
此方法用于创建一个由标签名称 tagName 指定的 HTML 元素,也就是上节课提到的元素(标签)节点。
如果想创建一个div
标签,我们可以使用:
const div = document.createElement('div');
创建文本方法**document.createTextNode(),
这个div
标签内部,添加纯文本内容
把txt
添加到div
中,把div
添加到body
中
const div = document.createElement('div');
const txt = document.createTextNode('优课达-学的比别人好一点');
div.appendChild(txt);
document.body.appendChild(div);
2. 添加新节点
appendChild(newNode)
inserBefore(newNode, referenceNode)
此方法和appendChild()
刚好相反,appendChild
是在所有儿子节点之后添加,inserBefore
是在某个目标儿子节点之前添加。
insertBefore(newNode, referenceNode)
,需要两个参数,newNode
表示新节点,referenceNode
表示目标节点,也就是新节点插入到目标节点之前。
3. 设置样式、属性
img.setAttribute('style', 'width: 100%; height: 100%;');
单独设置某些属性,如下代码:
dom.style.color = 'xxxx';
**setAttribute()**不仅仅可以设置style
之外,所有 HTML 属性都能用他设置,比如id
, src
, type
, disabled
, etc...
classList
classList
能获取到 DOM 上所有的类,所以我们也可以把样式写成css,然后再添加或删除class。
4. innerHTML
使用innerHTML = ''
清空select
节点所有的后代内容。
也可以利用innerHTML给某个元素添加内容。
function createDisease(txt) {
const dom = document.createElement('li');
// 我们可以直接用innerHTML设置其纯文本
dom.innerHTML = txt;
return dom;
}
DOM事件
DOM 绑定事件
// 监听Input输入事件
dom.addEventListener("input", function () {});
// 监听鼠标放置,移动事件
dom.addEventListener("mouseover", function () {});
// etc...
DOM 可以通过 addEventListener(eventName, callback)
绑定eventName
事件。
事件
焦点事件
focus: 表单组件(Input, Textarea, etc..)获取焦点事件 blur: 表单组件(Input, Textarea, etc..)失去焦点事件
鼠标事件
click: 点击事件 dblclick: 双击事件 mousedown: 在元素上按下任意鼠标按钮。 mouseenter: 指针移到有事件监听的元素内。 mouseleave: 指针移出元素范围外(不冒泡)。 mousemove: 指针在元素内移动时持续触发。 mouseover: 指针移到有事件监听的元素或者它的子元素内。 mouseout: 指针移出元素,或者移到它的子元素上。 mouseup: 在元素上释放任意鼠标按键。
键盘事件
keydown: 键盘按下事件 keyup: 键盘释放事件
视图事件
scroll: 文档滚动事件 resize: 窗口放缩事件
资源
load: 资源加载成功的事件
点击事件
// 默认是未点击喜欢
let hasLike = false;
const likeBtn = document.querySelector(".like-btn");
likeBtn.addEventListener("click", function () {
// 点击事件
hasLike = !hasLike;
console.log(hasLike);
});
冒泡
1.点击事件触发监听事件
2.冒泡找到其父亲节点,触发父亲节点的监听事件
3.依次冒泡直到html根元素为止。
阻止冒泡-e.stopPropagation();
// ......省略
likeBtn.addEventListener('click', function(e) {
// 点击事件
e.stopPropagation()
捕获
捕获和冒泡是完全相反的,冒泡是从当前元素沿着祖先节点往上冒泡,而捕获是从根 HTML 节点开始依次移动到当前元素。
我们上面使用的addEventListener
是在冒泡阶段监听事件,如果想在捕获阶段监听事件,我们需要传递第三个参数为true
, 代码如下
dom.addEventListener('click', function() {}, true);
委托
在大量子元素中单击任何一个都可以运行一段代码,可以将事件监听器设置在其父节点上,并让子节点上发生的事件冒泡到父节点上,而不是每个子节点单独设置事件监听器。
将
const box = document.querySelector('.box');
const imgArr = box.children;
for (let i = 0; i < imgArr.length; i++) {
imgArr[i].addEventListener('click', function() {
document.body.style.backgroundImage = `url(${imgArr[i].src})`;
});
}
修改为
const box = document.querySelector('.box');
box.addEventListener('click', function(e) {
// 注意box区域比img大,如果点击在空白间隔区域,那么返回的节点将不会是IMG,需要特殊处理一下
if (e.target.nodeName === 'IMG') {
document.body.style.backgroundImage = `url(${e.target.src})`;
}
});
移动事件
鼠标移动事件
mouseenter: 指针移到有事件监听的元素内。
mouseleave: 指针移出元素范围外(不冒泡)。
mousemove: 指针在元素内移动时持续触发。
mouseover: 指针移到有事件监听的元素或者它的子元素内。
mouseout: 指针移出元素,或者移到它的子元素上。
1. mousemove
这个是鼠标移动事件,比较简单
2. mouseenter/mouseleave
这个是鼠标进入和离开事件,但是仅仅只作用于当前 DOM 节点,不会作用于其后代节点
3. mouseover/mouseout
这个也是鼠标进入和离开事件,但和
enter/leave
不同的是:此事件除了作用于当前 DOM 节点,也会同时作用于其后代节点
表单元素事件
焦点事件
获取焦点和失去焦点两个事件 --- focus 和 blur。
内容值变化
监听元素内容变化 --- input 和 change。
const nick = document.querySelector('input.nick');
nick.addEventListener('input', function() {
console.log('-----input');
console.log(nick.value);
});
nick.addEventListener('change', function() {
console.log('-----change');
console.log(nick.value);
});
事件 | 介绍 | 案例 |
---|---|---|
change | 当用户提交对元素值的更改时触发; change 事件不一定会对元素值的每次更改触发 | 1. checkbox 值修改以后 2. select 选择后 3. input 内容修改并失去焦点 |
input | 只要 value 值修改就会触发 |
滚动事件
1. 无尽滚动
网页每次滚动到底部,会加载新内容,再次滚动到底部,又会加载新内容。
2. 动态效果
滚动一般用于展示一些动态效果,比如知乎头部
滚动事件,事件名称为 --- scroll。
键盘事件
keyboardEvent
KeyboardEvent
对象描述了用户与键盘的交互。每个事件都描述了用户与一个按键(或一个按键和修饰键的组合)的单个交互。