什么是DOM
DOM(Document Object Model)是文档对象模型, 是W3C组织推荐的出来可扩展标记语言(HTML或XML)的标准编程接口
当网页被加载时,浏览器会创建页面的文档对象模型。
W3C 已经定义了一系列的DOM接口, 通过这些DOM接口可以改变网页的内容, 结构, 样式
DOM被结构化为DOM树
- 文档 : 一个页面就是一个文档 , DOM中用document 表示
- 元素 : 页面中的所有标签都是元素 , DOM中用element表示
- 节点 : 网页中的所有内容都是节点 (标签, 属性, 文本, 注释 等) ,DOM中用node 表示
DOM把以上内容都看作对象
获取元素
- 通过id名获取
document.getElementById('id名')
(不加#号) - 通过标签获取
document.getElementsByTagName('元素名')
注意 :
- 返回的是获取过来元素对象的集合 以伪数组的形式存储 尽管只有一个或是没有这个元素 都是伪数组形式
- 想依次打印里面的元素对象我们可以采取遍历的方式
- 还可以获取某个元素(父元素)内部所有指定标签的子元素
element.getElementsByTagName('标签名')
父元素必须是单个对象(必须指明是哪一个元素对象) 获取的不包括父元素自己
遍历 :
var ul = document.getElementById('ul');
var lis = ul.getElementsByTagName('li');
for (var i = 0; i < lis.length; i++) {
console.log(lis[i]);
}
- 通过h5新增方法获取
document.getElementsByClassName('类名')
通过类名获取 括号里不用加'.'
document.querySelector(' ')
返回指定选择器的第一个元素对象 括号里需要加符号.box #nav
document.querySelectorAll(' ')
返回指定选择器的所有元素对象的集合 伪数组形式
- 获取body 和 html标签
document.body
获取body
document.documentElement
获取html
自定义属性
-
自定义属性目的 : 是为了保存并使用数据. 有些熟悉可以保存到页面中而不用保存到数据库
-
设置自定义属性 : 在html 标签里直接写下自定义属性
-
获取属性值
element.属性
得到的是官方属性值
var div = document.querySelector('div');
console.log(div.id);
element.getAttribute('index')
得到的是程序员自定义的属性
var div = document.querySelector('div');
console.log(div.getAttribute('index'));
- 重新修改属性值
element.属性 = '新属性值'
修改官方属性值
div.id = 'text';
element.setAttribute('index' , 新属性值)
修改的是程序员自定义的属性值
div.setAttribute('index' , 2);
- 删除属性
element.removeAttribute('index')
div.reomveAttribute('index');
- h5新增自定义属性方法
dataset 是一个集合 里面存放了所有以data开头的自定义属性
<div data-index = "2" data-last-name = "andy"><div>;
//如果自定义属性有多个连接词 我们获取的时候采取驼峰命名法 并且'data' 不用写
console.log(div.dataset.lastName);
//或者
console.log(div.dataset['lastName']);
//或者
console.log(div.getAttribute('data-last-name'));
事件
- 事件定义
什么是事件
JS使我们有能力创建动态页面 , 而事件使可以被JS侦测到的行为
简单理解 : 触发—相应机制
网页中的每个元素都可以产生某些可以触发JS的事件 , 例如 , 我们可以在用户点击某个按钮时产生一个事件 , 然后去执行某些操作
- 事件三要素
- 事件源 : 事件被触发的对象
- 事件类型 如何触发 (比如鼠标经过还是鼠标点击)
- 事件处理程序 通过一个函数赋值的方式完成
btn.onclick = function() {
alert('啦啦啦');
}
- 事件执行过程
- 点击事件源
- 绑定事件 或者叫注册事件
- 添加事件处理程序
- 事件操作
- 一些常用的绑定事件操作
事件 | 描述 |
---|---|
onclick | 鼠标点击 |
onmouseover | 鼠标经过 |
onmouseout | 鼠标离开 |
onfocus | 获得光标 |
onblur | 失去光标 |
onchange | 当用户改变输入字段内容时 |
onmousedown | 鼠标按下 |
onmouseup | 鼠标弹起 |
- 事件操作元素(写在function(){}里面的处理程序)
- 操作元素内容
innerHTML
和innerText
都可以获取元素的内容
区别 :
innerText
不识别htnl标签 非标准 去除空格和换行
innerHTML
识别html标签 W3C标准 保留空格和换行
所以我们常使用innerHTML
div.innerHTML = '' //修改
div.innerHTML //获取
- 操作常见元素属性
src
, href ,
title
, alt
可获取和修改 element.元素属性
- 操作表单元素属性
type
, value
, disabled
等
可获取和修改 element.元素属性
- 操作元素样式属性
我们可以通过js修改元素的大小, 颜色 , 位置等样式
element.style
, className
注意 :
- js里面的样式采取驼峰命名法 比如 fontSize backgroundColor
- js修改style 样式操作 , 产生的是行内样式 , css权重比较高
div.stlye.backgroundColor = 'red';
div.stlye.fontSize = '26px';
当修改的样式多时 可以用classNme
div.className = '类名'
(没有 '.'
)
注意 : 当添加了
classNmae
之后 就会覆盖原先的类名
要想同时兼顾 我们可以这样写
div.className = 'first change'
节点操作
-
为什么学节点操作
前面获取元素的方法
document.getElementById('id名')
,document.getElementByTagName('')
,document.querySelector('')
逻辑性不强 , 繁琐
利用节点层级关系(父子兄关系)获取元素 逻辑性强 操作简单 但兼容性较差 -
节点概述
一般, 节点至少拥有nodeType(节点类型) , nodeName(节点名称) 和nodeValue(节点值) 这三个基本属性
- 元素节点 nodeType为1
- 属性节点nodeType为2
- 文本节点 nodeType为3 (包含文字 , 空格 , 换行等)
实际开发中 , 我们操作的主要是元素节点
- 父节点
parentNode
获得的是离元素最近的父级节点(亲爹)
console.log('div.parentNode');
- 子节点
parentNode.childNodes
返回包含指定节点的子节点的集合 , 该集合为及时更新的集合
注意 :
返回的值里面包含了所有的子节点 , 包括元素节点 , 文本节点 所以 , 如果只想获取里面的元素节点 , 需要专门处理 . 麻烦, 所以我们一般不提倡使用childNodes
特殊处理 :
var ul = document.querySelector('ul');
for (var i = 0; i < ul.childNodes.length; i++) {
if (ul.childNodes[i].nodeType === 1) {
console.log(ul.childNodes[i]);
}
}
firstChild
获取第一个元素lastChild
最后一个元素 不管是文本节点还是元素节点firstElementChild
获取第一个元素lastElementChild
最后一个元素 获取元素节点children
获取所有的子元素节点 是我们实际开发常用的
我们用children[0]
来获取第一个元素
- 兄弟节点
node.nextElementSibling
返回当前元素下一个兄弟元素节点 , 找不到就返回null
node.previousElementSibling
返回当前元素上一个兄弟元素节点 , 找不到就返回null
注意 : 这两个方法有兼容性问题 IE9以上才支持 - 创建节点
var li = document.createElement('li')
创建节点
父节点.insertBefore(li, 添加到谁前面)
添加节点
父节点.appendChild(li)
添加节点
//创建一个li
var li = document.createElement('li');
//赋值
li.innerHTML = text.value + "<a href='javascript:;'>删除</a>";
//添加到里面insertBefore 添加到前面
ul.insertBefore(li, ul.children[0]);
// ul.appendChild(li);添加到后面
动态创建元素
element.innerHTML
将内容写入某个DOM节点 , 不会导致页面全部重绘 当采取数组形式拼接时(不要拼接字符串) 创建多个元素 与其它方法相比 效率最高 结构稍复杂document.write()
直接将内容写入页面的内容流 , 但是文档执行完毕 , 它会导致页面重绘document.createElement()
创建多个元素效率稍低 但结构清晰
数组形式拼接 :
function fun() {
var array = [];
for (var i = 0; i < 1000; i++) {
array.push('<div>111</div>');
}
document.body.innerHTML = array.join('');
}
fun();
- 克隆节点
node.cloneNode()
括号为空或者是false 浅拷贝 只复制标签不复制里面的内容
node.cloneNode(true)
括号为true 深拷贝 复制标签和里面的内容
var li = ul.children[0].cloneNode(true);
ul.appendChild(li);
- 删除节点
node.removeChild(child)
删除元素
ul.removeChild(ul.children[0]);
监听事件
给元素注册事件 , 称为注册事件或绑定事件 有两种方式
传统方式和方法监听注册方式
传统注册方式 :
- 利用on开头的事件 (onclick)
<button onclick="alert('hi~')"></button>
或者btn.onclick = function() {}
- 注册事件唯一 同一个元素同一个事件只能设置一个处理函数 , 最后注册的处理函数将会覆盖前面注册的处理函数
- 事件监听方式 :
eventTarget.addEventListener(type, listener[, useCapture])
eventTarget.addEventListener()
方法将指定的监听器注册到eventTarget(目标对象)上 , 当该对象触发指定事件时 , 就会执行事件处理函数
type
: 事件类型字符串 , 比如click , mouseover 注意这里不要带onlistener
: 事件处理函数 , 事件发生时 , 会调用该监听函数useCapture
: 可选参数 , 是一个布尔值 , 默认是false , DOM事件流之后再详细解释
注意
- 监听方法注册事件 是W3C推荐方式 , 但IE9以上才支持
addEventListener()
是一个方法- 特点 : 同一个元素同一个事件可以注册多个监听器 按注册顺序一次执行
- 传统删除事件 :
div.onclick = function() {
alert(11);
div.onclick = null;
}
- 监听事件删除
div.addEventListener('click' , fn) // 里面的fn不用调用加小括号
function fn() {
alert(22);
div.removeEventListener('click', fn);
}
事件对象
- 什么是事件对象 :
官方解释 : event
对象代表事件的状态 , 比如键盘按键的状态 , 鼠标的位置 , 鼠标按钮的状态
简单理解就是 事件发生后 , 跟事件相关的一系列信息数据的集合都放到了这个对象里面 , 这个对象就是事件对象event
, 它有很多属性和方法
- 写法 :
div.addEventListener('click', function(e) {
alert('11');
})
注意 :
event
就是一个事件对象 , 写到侦听函数的小括号里面 , 当形参来看- 事件对象只有有了事件才会存在 , 是系统自带的 , 不需要我们传递参数
- 这个事件对象我们可以自己命名 比如 event , evt ,e 我们常用
e
- 事件对象也有兼容性问题
- 事件对象的常见属性和方法
e.target
和this
的区别
e.target
指向的是我们点击的那个对象this
指向的是我们绑定的那个对象- 在事件委托里 有区分出来
- 阻止默认行为
常见的 让链接不跳转 , 或者让提交的按钮不提交
a.addEventListener('click',function(e) {
e.preventDefault(); //DOM标准写法 有兼容性问题
})
// 我们利用return false 也能阻止默认行为 没有兼容性问题
//特点 : return后面的代码不执行了 , 而且仅限于传统的注册方式
阻止默认行为之 禁用右键 和 禁止选中文字
contextmenu
禁用右键
selectstart
禁止选中文字
//禁用右键
document.addEventListener('contextmenu',function(e) {
e.preventDefault();
})
//禁止选中文字
document.addEventListener('selectstart',function(e) {
e.preventDefault();
})
事件对象之键盘事件
几个触发事件的操作
keyup
弹起时触发 (不区分大小写)keypress
按下时触发 不能触发功能键 比如 ctrl shift (区分大小写)keydown
按下时触发 能识别功能键 比如 ctrl shift (不区分大小写)- 三个的执行顺序 : keydown - keypress - keyup
- 键盘事件对象的一个属性 :
keyCode
返回该键的ASCII值 (能区分大小写 会返回不同的ASCII值)
//检测是否按下了s键
document.addEventListener('keyup',function(e) {
if (e.keyCode === 83) {
alert(s);
}
})
事件对象之鼠标事件对象
client
鼠标在可视区的x y坐标page
鼠标在页面文档的x y坐标screen
鼠标在电脑屏幕的x y坐标
document.addEventListener('click',function(e) {
console.log(e.clientX);
console.log(e.clientY);
console.log(e.pageX);
console.log(e.pageY);
console.log(e.screenX);
console.log(e.screenY);
})
事件流
事件流描述的是从页面中接收事件的顺序
事件发生时会在元素节点之间按照特定的顺序传播 , 这个传播过程即DOM事件流
DOM事件流分三个阶段
- 捕获阶段
- 当前目标阶段
- 冒泡阶段
事件冒泡 : 事件开始时由最具体的元素接收 , 然后逐级向上传播到DOM最顶层节点的过程
注意 :
- JS只能执行捕获或者冒泡其中的一个阶段
onclick
和attachEvent
只能得到冒泡阶段addEventListener(type, lidtener[, useCapture])
第三个参数如果时true
, 表示在事件捕获阶段调用事件处理程序
如果是false
(默认不写就是false), 表示在事件冒泡阶段调用事件处理程序- 实际开发中我们很少使用事件捕获, 更关注事件冒泡
- 有些事件是没有冒泡的 , 比如
onblur
,onfocus
,onmouseenter
,onmouseleave
- 事件冒泡有时候会带来麻烦 , 有时又会帮助很巧妙的做某些事件
- 阻止冒泡的兼容性写法
if(e && e.stopPropagation) {
e.stopPropagation();
}else {
window.event.cancelBubble = true;
}
- 冒泡带来的帮助 : 事件委托
事件委托 又叫事件代理 , 在jQuery里叫事件委派
事件委托原理 : 不是每个子节点单独设置事件监听器 , 而是事件监听器设置在其父节点上 ,然后利用冒泡原理影响设置每个子节点
事件委托好处 : 只操作了一次DOM , 提高了程序的性能