【前端】前端三要素之DOM

2024-02-21 12:28
文章标签 前端 frontend dom 三要素

本文主要是介绍【前端】前端三要素之DOM,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

写在前面:本文仅包含DOM内容,JavaScript传送门在这里,BOM传送门在这里。

本文内容是假期中刷的黑马Pink老师视频(十分感谢Pink老师),原文保存在个人的GitLab中,如果需要写的网页内容信息等可以评论联系我,若是编辑博文中出现了忘记上传的图片或者错位的图片欢迎评论区指正。写作不易,欢迎点赞、收藏+关注。

文章目录

  • DOM
    • DOM 专有名词
        • DOM树
    • DOM 获取元素
  • DOM | 事件
    • 点击按钮事件示例
    • 执行事件过程
    • 鼠标到Div上跳出弹框示例
  • 操作元素
    • 修改元素内容
    • 示例 | 鼠标移动进去显示中文,离开显示英文
    • 区别 | innerText 与 innerHTML 的区别
    • 通过innetText 和 innerHTML 获取文字内容
        • innerText
        • innerHTML
    • 修改元素属性
    • 表单属性操作
        • 修改表单文字
        • 示例 | 输入密码
    • 表单样式修改
        • 示例 | 修改背景颜色
        • 示例 | 淘宝精灵图
        • 示例 | 得到焦点与失去焦点
    • 使用`className`修改样式
    • 自定义属性值
  • 节点操作
    • node.parentNode | 获取父节点
    • node.childNodes | 获取子节点
    • 获取特定子节点
    • 获取兄弟节点
        • 获取下一个兄弟节点
        • 获取上一个兄弟节点
    • 创建节点
    • 删除节点
    • 拷贝节点
    • `document.write()` | 不推荐
  • 监听事件
    • 方式比较:
        • 传统方式
        • 监听事件
    • 添加监听事件
    • 解绑事件
  • 事件流
    • 事件执行流程
        • 捕获阶段
        • 目标节点
        • 冒泡阶段
    • 验证
  • 事件对象
    • 获取事件对象
        • 传统方式获取事件对象
        • 监听方式获取事件对象
        • 在ie678中使用监听对象
    • 事件对象的常见属性和方法
    • 阻止默认行为
  • 阻止冒泡事件
  • 事件委托
        • 示例
  • 禁用鼠标右键
  • 禁用文字选择
  • 获取鼠标坐标信息
  • 常用键盘事件
        • `keydown` | 键盘被按下
        • `keyup` | 键盘弹起事件
        • `keypress` | 键盘按下事件
    • 按下s键输入框获取焦点案例

DOM

DOM 专有名词

DOM树
  1. 文档:一个页面就是一个文档,DOM中使用Document表示
  2. 元素:页面中所有的标签都是元素,DOM中使用element表示
  3. 节点:网页中所有内容都是节点(标签、属性、文本、注释等),DOM中使用node表示

在这里插入图片描述

DOM 把以上内容都看做事对象。

DOM 获取元素

  1. 通过ID获取 | getElementById()
  2. 通过标签名获取
  3. 通过HTML5新增方法获取
  4. 特殊元素获取
  1. 通过ID获取 | getElementById()

返回的是一个

<body><div id="time">2019-9-9</div><script>var time = document.getElementById('time');console.log(time);console.log(typeof time); // 返回的是一个元素对象console.log(time.id);console.dir(time); // div#time</script>
</body>
  1. 根据标签名获取 | getElementsByTagName() | 返回的是对象集合
<body><ul><li>知否知否,应是绿肥红瘦。</li><li>知否知否,应是绿肥红瘦。</li><li>知否知否,应是绿肥红瘦。</li><li>知否知否,应是绿肥红瘦。</li><li>知否知否,应是绿肥红瘦。</li></ul><script>var eles = document.getElementsByTagName('li');console.log(eles); // HTMLCollections(5) [li,li,li,li,li]// 逐个输出一下for( var i = 0; i < eles.length ; i ++) {console.log(eles[i]);}</script>
</body>

得到元素对象是动态的,如果元素的内容发生了变化,JS获取到的内容跟着一起变化

注意事项

  1. 如果页面中只有一个元素,返回的也是一个伪数组
  2. 如果页面中没有元素,返回的是一个空的伪数组

通过父元素获取其全部子元素

<body><ul><li>知否知否,应是绿肥红瘦。</li><li>知否知否,应是绿肥红瘦。</li><li>知否知否,应是绿肥红瘦。</li><li>知否知否,应是绿肥红瘦。</li><li>知否知否,应是绿肥红瘦。</li></ul><ol><li>哈哈哈</li><li>哈哈哈</li><li>哈哈哈</li><li>哈哈哈</li></ol><script>var ol = document.getElementsByTagName('ol');var lis = ol[0].getElementsByTagName('li');console.log(lis);</script>
</body>
  1. HTML5新增的方法 | 通过类名获取 | getElementsByClassName()
<body><div class="box">123</div><div class="box">123</div><div class="box">123</div><script>var lis = document.getElementsByClassName('box'); // 长度为3的伪数组</script>
</body>
  1. querySelectir()
  1. querySelector():获取指定选择器的第一个元素
  2. querySelectorAll():获取页面上所有元素
<body><div class="box">hahaha</div><div class="box">hahaha</div><div class="box">hahaha</div><script>var firstBox1 = document.querySelector('.box'); // 通过.告诉选择器这是一个class | <div class="box">hahaha</div>var firstBox2 = document.querySelector('#box'); // 通过#告诉选择器这是一个id | nullconsole.log(firstBox1);console.log(firstBox2);</script>
</body>
  1. querySelectirAll() | 获取所有元素
<body><div class="box">hahaha</div><div class="box">hahaha</div><div class="box">hahaha</div><script>var firstBox1 = document.querySelectorAll('.box'); // 通过.告诉选择器这是一个class | <div class="box">hahaha</div>var firstBox2 = document.querySelectorAll('#box'); // 通过#告诉选择器这是一个id | nullconsole.log(firstBox1); // 长度为3的伪数组console.log(firstBox2); // 空的伪数组</script>
</body>
  1. 获取特殊标签 | body、htlm

一般来说只有一个body标签或者一个htlm标签

  1. 获取 BODY
<body><script>var bodyEle = document.body;console.log(bodyEle); // 输出Body对象</script>
</body>
  1. 获取 HTML
<body><script>var htmlEle = document.documentElement;console.log(htmlEle); // HTML 对象</script>
</body>

DOM | 事件

JavaScript 使我们有能力创建动态页面,而时间是可以被JavaScript侦测到的行为

简单理解:出发—响应机制

网页中的每个元素都可以产生某些可以出发JavaScript的事件,例如,我们可以在用户点击某个按钮的时候产生一个事件,然后去执行某些操作。

事件是由三部分组成:事件源、事件类型、事件处理程序(一般称为事件三要素)

  1. 事件源:时间的触发的对象,是由谁来触发,比如按钮
  2. 事件类型:如何出发,比如鼠标点击出发、鼠标经过出发、键盘按下触发
  3. 事件处理程序:通过一个函数赋值的方式完成

点击按钮事件示例

<body><button id="btn">点击一下</button><script>var btn = document.getElementById('btn');btn.onclick = function () {alert('点击了一下~');}</script>
</body>

执行事件过程

  1. 获取事件源
  2. 注册时间(绑定事件)
  3. 添加事件处理程序(采用函数赋值形式)

鼠标到Div上跳出弹框示例

<body><div style="background: antiquewhite;text-align: center;width: 200px;border-radius: 5px;box-shadow: 0 0 3px gray">123</div><script>var div = document.querySelector('div');div.onmouseover = function (){alert('Hello World~');}</script>
</body>
鼠标事件描述
onclick鼠标点击左键触发
onmouseover鼠标经过触发
onmouseenter鼠标进入触发
onmouseout鼠标离开触发
onfocus获取鼠标焦点触发
onblur失去鼠标焦点触发
onmousemove鼠标移动触发
onmousedown鼠标按下触发
onmouseup鼠标弹起触发
contextmenu右键的时候触发
selectstart选择文字的时候触发

注意:mouseover存在冒泡事件,经过自身盒子会触发事件,子盒子也会触发。mouseenter不存在冒泡事件,只有经过自身时才会触发。

操作元素

修改元素内容

  1. element.innerText | 起始位置稻种植未知的内容,但它去除Html标签,同时空格和空行也会去掉
  2. element.innerHTML | 起始位置到终止位置的全部内容,包括html,同时保留空格和换行

示例 | 鼠标移动进去显示中文,离开显示英文

<body><button>显示中文</button><div style="background: antiquewhite;border: .1px solid gray">Hello World</div><script>//1. 获取元素var btn = document.querySelector('button');var div = document.querySelector('div');btn.onmouseover = function () {div.innerText = '你好,世界!'}btn.onmouseleave = function () {div.innerText = 'Hello World'}</script>
</body>

鼠标移动上去显示中文,鼠标移出之后显示英文。

在这里插入图片描述

区别 | innerText 与 innerHTML 的区别

innetText:它会原封不动的将我们给它的字符串显示到页面上(无法识别HTML标签)

innerHTML:如果发现是html标签,它会解析html标签并显示

尽量使用innerHTML,这是W3C发布的标准

<body><button>点击加粗名字</button><div>我是Jim.kk</div><script>var btn = document.querySelector('button');var div = document.querySelector('div');btn.onclick = function () {div.innerHTML = '<b>我是Jim.kk</b>';}</script>
</body>

在这里插入图片描述

如果是使用innerText的方式的话,则会原封不动的显示双引号的内容,下面看示例:

<body>
<button>点击加粗名字</button>
<div>我是Jim.kk</div>
<script>var btn = document.querySelector('button');var div = document.querySelector('div');btn.onclick = function () {div.innerText = '<b>我是Jim.kk</b>';}
</script>
</body>

在这里插入图片描述

通过innetText 和 innerHTML 获取文字内容

两者的区别在于:innerText只会获取文字

innerText
<body><p>一段文字:<span>我是Jim.kk</span></p><script>var p = document.querySelector('p');console.log(p.innerText); // 一段文字: 我是Jim.kk</script>
</body>

在这里插入图片描述

innerHTML
<body><p>一段文字:<span>我是Jim.kk</span></p><script>var p = document.querySelector('p');console.log(p.innerHTML); // 一段文字:(换行)<span>我是Jim.kk</span></script>
</body>

在这里插入图片描述

修改元素属性

  1. src、href
  2. id、alt、title
<body><button id="btn1">图片1</button><button id="btn2">图片2</button><div style="margin-top: 20px"><img src="img/img1.png" alt="" style="width: 500px" title="IMG1"></div><script>// 修改图片属性var btn1 = document.getElementById('btn1');var btn2 = document.getElementById('btn2');var img  = document.querySelector('img');btn1.onclick = function () {img.src = 'img/img1.png';img.title = 'IMG1';}btn2.onclick = function () {img.src = 'img/img2.png';img.title = 'IMG2';}</script>
</body>

以上代码点击按钮2显示一张图片,点击按钮1又会变回来

表单属性操作

修改表单文字

type、value、checked、selected、disabled

<body><input type="text" value="请输入内容"><button id="btn1">按钮</button><button id="btn2">禁用</button><script>// 1. 获取元素var btn1 = document.getElementById('btn1');var btn2 = document.getElementById('btn2');var input = document.querySelector('input');btn1.onclick = function () {input.value = '123';}btn2.onclick = function () {input.disabled = true;this.disabled = true;  // this指向的是btn,谁调用函数就指向谁,这里是btn2}</script>
</body>

在这里插入图片描述

示例 | 输入密码

点击小眼睛显示密码,同时小眼睛睁开
再次点击隐藏密码,同时小眼睛关闭

<body><div class="box"><label for=""><img src="img/icons/close.png" alt="" id="eye"></label><input type="password" name="" id="pwd"></div><script>var btn = document.getElementById('eye');var pwd = document.getElementById('pwd');var flag = 0;btn.onclick = function () {if(flag === 0) {this.src = 'img/icons/open.png'pwd.type='text';flag = 1;} else {this.src = 'img/icons/close.png'pwd.type='password';flag = 0;}}</script>
</body>

表单样式修改

可以用以下两种方式修改:

  1. element.style='background: red';
  2. element.style.background='red';

区别在于,第一种方式可以在引号内写入很多样式,第二种需要一个样式定义一行

示例 | 修改背景颜色

设置一个DIV,鼠标移入之后改变背景颜色,示例如下:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>样式操作1</title><style>div {width: 200px;height: 200px;background: antiquewhite;}</style>
</head>
<body>
<div></div>
<script>var div = document.querySelector('div');div.onmouseover = function () {div.style = 'background: red';}div.onmouseleave = function () {div.style = 'background: antiquewhite';}
</script>
</body>
</html>

或者像下面这么写:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>样式操作2</title><style>div {width: 200px;height: 200px;background: antiquewhite;}</style>
</head>
<body><div></div><script>var div = document.querySelector('div');div.onmouseover = function () {div.style.background = 'red';}div.onmouseleave = function () {div.style.background = 'antiquewhite';}</script>
</body>
</html>
示例 | 淘宝精灵图
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>淘宝精灵图案例</title><style>* {margin: 0;padding: 0;}li {list-style-type: none;}.box {;width: 250px;margin: 100px auto;}.box li {float: left;width: 24px;height: 24px;background: pink;margin: 15px;background: url(img/icons/sprite.png) no-repeat;}</style>
</head>
<body><div class="box"><ul><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li></ul></div><script>// 1. 获取所有livar lis = document.querySelectorAll('li');for (var i = 0; i < lis.length ; i++){// 让索引号*44获取每个li的背景y坐标var index = i * 44;lis[i].style.backgroundPosition = '0 -' + index + 'px'}</script>
</body>
</html> 
示例 | 得到焦点与失去焦点

以下示例有一个磨人的输入框,若是输入框的默认值是’手机’,则在得到焦点的时候清空输入框,若是失去焦点的时候输入框内容是空的,则显示手机。

<body><input type="text" value="手机"></input><script>var input = document.querySelector('input');input.onfocus = function () {// console.log('得到焦点');if ( input.value === '手机' ) {this.value = '';}}input.onblur = function () {if ( input.value === '' ) {input.value = '手机';}}</script>
</body>

使用className修改样式

上述方法是一条一条的style属性,除了以上方法外,我们还可以同时定义多个div,然后通过element.className='divName'的方式修改它的样式

如果想要即保留原来的类名,有来个新的类名,只需要element.className='oldDivName newDivName'

下面源码是个很好的示例:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>className</title><style>.div1{height: 50px;background: antiquewhite;box-shadow: 0 0 5px gray;border: 3px solid gray;border-radius: 5px;}.div2{height: 100px;background: red;box-shadow: 0 0 20px gray inset;border: .1px solid gray;border-radius: 50px;}</style>
</head>
<body><div class="div1"></div><script>var div = document.querySelector('div');div.onmouseenter = function () {div.className = 'div2';}div.onmouseleave = function () {div.className = 'div1';}</script>
</body>
</html>

自定义属性值

  1. 通过element.getAttribute('')可以获取属性
  2. 这种方式可以获取自定义属性
  3. 通过element.setAttribute('属性名','属性值'')可以为元素自定义属性
  1. 通过getAttribute获取自定义属性值

div中本来是不存在index这个内置属性的,但是我们设置之后可以通过getAttribute来获取:

<body><div index="1" id="div1"></div><script>var div = document.querySelector('div');console.log(div.getAttribute('id')); // div1console.log(div.getAttribute('index')); // 1</script>
</body>
  1. 通过setAttribute设置自定义属性

除了直接将自定义属性写在标签里面以外,还可以通过setAttribute的方式设置自定义属性

<body><div id="div1"></div><script>var div = document.querySelector('div');div.setAttribute('xx','123');console.log(div.getAttribute('xx')); // 123// 修改内置属性值div.setAttribute('id','divx');console.log(div.getAttribute('id')); // divx</script>
</body>
  1. H5 新标准

H5新标准中,规定所有的自定义属性都得以data-开头,所以又新增了dataset方法让我们获取自定义属性

这种方法只能获取data-开头的自定义属性

<div data-index="1" data-list-name="Jim.kk"></div>
<script>var div = document.querySelector('div');console.log(div.dataset.index); // 1console.log(div.dataset['index']) // 1console.log(div.dataset.listName); // Jim.kkconsole.log(div.dataset['listName']) // Jim.kk
</script>

节点操作

什么是节点?网页中所有的内容都是节点(标签、属性、文本、注释等),在DOM中,节点使用node来表示。

HTML DOM树种的所有节点均可通过JavaScript进行访问,所有的HTML元素(节点)均可被修改,也可以被创建或者删除。

节点一般由:nodeType(节点类型)、nodeName(节点名称)和nodeValue(节点值)这三个基本属性。

在这里插入图片描述

以上截图对应以下代码(注意,由于没有规定编码,在浏览器中打开可能存在乱码):

<html lang="en"><head><title>节点操作</title></head><body><a href="www.baidu.com">我的链接</a><h1>我的标题</h1></body>
</html>

利用DOM树可以把节点划分为不同的层级关系,常见的是父子兄层级关系。

node.parentNode | 获取父节点

<body><div><span>新年快乐!龙年行大运!!!</span></div><script>var span = document.querySelector('span');var div = span.parentNode;console.log(div);</script>
</body>

node.childNodes | 获取子节点

childNode默认会获得所有的子节点,包括文字和标签,所以以下代码输出的node长度为9(有五个换行)

如果不想要换行(毕竟也没什么用),可以使用children来代替childNode

children并不是官方的,但是获得了各浏览器的支持,所以放心使用。

<body><ul><li>新年快乐!龙年行大运!!!</li><li>新年快乐!龙年行大运!!!</li><li>新年快乐!龙年行大运!!!</li><li>新年快乐!龙年行大运!!!</li></ul><ul><li>我是Jim.kk!!!</li><li>我是Jim.kk!!!</li><li>我是Jim.kk!!!</li><li>我是Jim.kk!!!</li></ul><script>var ul = document.querySelector('ul');console.log(ul.childNodes); // NodeList(9) [text, li, text, li, text, li, text, li, text]console.log(ul.children); // HTMLCollection(4)</script>
</body>

获取特定子节点

可以使用firstChild来获取第一个节点,但是这种获取方式仍然会获取换行等文本节点

方法说明备注
element.firstChild获取第一个元素,但是会包含文本信息,也就是会获取你的换行等信息
element.lastChild获取最后一个元素,但是会包含文本信息,也就是会获取你的换行等信息
element.firstElementChild获取第一个元素,不包含文本信息,也就是只获取标签元素IE9以上才支持
element.lastElementChild获取最后一个元素,不包含文本信息,也就是只获取标签元素IE9以上才支持
element.children[0]用下标的方式获取某个指定的元素实际开发中的用法

获取兄弟节点

获取下一个兄弟节点
方法说明备注注意
nextSibling获取下一个兄弟节点也会获取text节点
nextElementSibling获取下一个兄弟节点只会获取标签节点IE9以上才支持
<body><div>新年快乐!龙年行大运</div><span>我是Jim.kk</span><script>// 下一个兄弟节点存在var div = document.querySelector('div');console.log(div.nextSibling) // #textconsole.log(div.nextElementSibling) // span// 下一个兄弟节点是Scriptvar span = document.querySelector('span');console.log(span.nextSibling) // #textconsole.log(span.nextElementSibling) // <script>// 下一个兄弟节点不存在var script = document.querySelector('script');console.log(script.nextSibling) // <link type="text/css" rel="stylesheet" id="dark-mode-custom-link">console.log(script.nextElementSibling) // <link type="text/css" rel="stylesheet" id="dark-mode-custom-link"></script>
</body>
获取上一个兄弟节点
方法说明备注注意
previousSibling获取上一个兄弟节点也会获取text节点
previousElementSibling获取上一个兄弟节点只会获取标签节点,如果不存在则会返回nullIE9以上才支持
<body><div>新年快乐!龙年行大运</div><span>我是Jim.kk</span><script>var span = document.querySelector('span');console.log(span.previousSibling); // #textconsole.log(span.previousElementSibling); // <div>新年快乐!龙年行大运</div>// 当前节点是第一个节点,会获取一个空var div = document.querySelector('div');console.log(div.previousSibling) // #textconsole.log(div.previousElementSibling) // null</script>
</body>

创建节点

  1. 创建一个节点 | document.createElement();
  2. 添加到某个地方去
    2.1 fatherElement.appendChild(childElement); | 在父节点内部追加节点
    2.2 fatherElement.insertBefore(childElement,fatherElement.children[0]); | 在父节点内部的某个子节点前面插入这个元素
<body><ul></ul><script>var li1 = document.createElement('li');var ul = document.querySelector('ul');ul.appendChild(li1); // 在ul的子节点中追加这个元素var li2 = document.createElement('li');ul.insertBefore(li2,ul.children[0]); // 在ul的0号元素前面插入一个li2</script>
</body>

删除节点

  1. node.removeChild() | 删除父亲中的某个孩子
<body><ul><li>兔年</li> <!-- 打错了,删除掉 --><li>龙年</li><li>行大运</li></ul><script>// 1. 获取元素var ul = document.querySelector('ul');// 2. 删除元素ul.removeChild(ul.children[0]);</script>
</body>

拷贝节点

我们可以使用node.cloneNode()来拷贝节点,但是如果括号中为空或者是false,则只会克隆节点本身,而不会克隆里面的子节点,如果想要克隆里面的子节点,我们在括号内写入true即可。

<body><ul><li>1</li><li>2</li><li>3</li></ul><script>var ul = document.querySelector('ul');// 1. node.cloneNode();var li1 = ul.children[0].cloneNode();ul.appendChild(li1); // 节点为空 | 因为上面的括号参数为空或者false,是浅拷贝,则只克隆节点本身,不克隆里面的子节点var li2 = ul.children[0].cloneNode(true);ul.appendChild(li2); // 节点为空 | 因为上面的括号参数为空或者false,是浅拷贝,则只克隆节点本身,不克隆里面的子节点</script>
</body>

document.write() | 不推荐

document.write是直接将内容写入页面的内容流,但是文档流执行完毕,会导致页面全部重绘。

简单解释下:若是我们在页面加载的时候就直接在script中写入document.write,那么里面的元素会追加在页面的最下面,但是若是通过页面中一个按钮点击后再加载的话,那么整个页面会只剩下这一个元素。

示例如下:

  1. 直接加载元素
<body><p>abc</p><script>var btn = document.querySelector('button');document.write('<div>我是Jim.kk</div>');</script>
</body>

在这里插入图片描述

可以看到,由于页面加载的时候就已经执行了这个方法,所以该方法中的内容是被追加到页面最下面的。

<body><button>点击</button><p>abc</p><script>var btn = document.querySelector('button');btn.onclick = function () {document.write('<div>我是Jim.kk</div>')}</script>
</body>

在这里插入图片描述

由于页面已经渲染完毕,这时候我们点击按钮写入这个元素,页面中的内容直接被覆盖了,只留下了我们写入的元素(建议自己试验一下试试效果)。

监听事件

给元素添加事件,称为注册事件或者绑定事件

注册事件有两种方式:传统方式方法监听注册方式

方式比较:

传统方式
  1. 传统方式利用on开头的事件,比如onclickonmouseenter
  2. 特点:注册事件的唯一性
  3. 同一个元素同一个事件只能设置一个处理函数,最后注册的处理函数会覆盖前面注册的处理函数。

下面代码中,由于我们给btn先后注册了两个点击事件,所以后面的点击事件会覆盖掉前面的点击事件,点击之后会跳出弹框’Hello~’

<body><button>点击</button><script>var btn = document.querySelector('button');btn.onclick = function () {alert('Hi~')}btn.onclick = function () {alert('Hello~')}</script>
</body>

在这里插入图片描述

监听事件
  1. W3C 标准 推荐方式
  2. addEventListener() 是一个方法
  3. IE9之前的IE浏览器不支持此方法,可以使用attachEvent()代替
  4. 同一个元素,同一个事件可以添加多个

添加监听事件

书写方式: eventTarget.addEventListener(type,listener[,useCapture])
eventTarget.addEventListener() 方法将制定的监听器注册到eventTarget上(目标对象),当该对象出发指定的事件时,就会执行事件处理函数。

  1. type:事件类型字符串,比如clickmouseover,注意这里不带on
  2. listener:事件处理函数,事件发生时,会调用该监听函数
  3. useCapture:可选参数,是一个布尔值,默认是false。

添加监听事件的两个方法:

方法说明备注
addEventListenerIE9以后才支持推荐
attachEventIE9以前才支持
<body><button>监听事件</button><script>// 2. 监听事件var btn = document.querySelector('button');btn.addEventListener('click',function () {alert('Hello World');})btn.addEventListener('click',function () {alert('我是Jim.kk');})</script>
</body>

以上代码点击按钮之后,会连续跳出两次弹框,第一个弹框显示Hello World,当你关闭该弹框之后,会再次跳出一个弹框,显示我是Jim.kk

解绑事件

  1. 传统方式中,我们可以使用element.onclick = null的方式解绑事件
  2. 监听事件中,我们要移除事件,就不能再用匿名函数了,而是要给函数一个名字,然后removeEventListener这个事件
<body><!-- 传统方式 --><button id="btn1">传统事件</button><script>var btn = document.querySelector('#btn1');btn.onclick = function () {alert('我是Jim.kk');btn.onclick = null; // 解绑事件,再次点击就没用了}</script><!-- 监听方式 --><button id="btn2">监听方式</button><script>var btn = document.querySelector('#btn2');function fun() {alert('Jim.kk祝大家新年快乐!!');btn.removeEventListener('click',fun)}btn.addEventListener('click',fun);</script>
</body>

在IE9之前的浏览器中,我们只能使用attachEvent添加监听函数,在这种情况下我们要使用detachEvent的方式来移除事件,用法与removeEventListener无异,这里不做演示。

事件流

事件执行流程

事件流描述的是从页面中接收事件的顺序
事件发生时会在元素节点之间按照特定的顺序传播,这个传播过程即DOM事件流。
比如我们给DIV注册了点击事件
DOM事件流分为三个阶段:

  1. 补货阶段
  2. 当前目标节点
  3. 冒泡阶段

在这里插入图片描述

捕获阶段
  1. 虽然我是给Div添加的点击事件,但是点击事件的接收者是Document
  2. Document并没有绑定这个点击事件,接下来向下找,找到html
  3. html也没有绑定,继续向下找找到body
  4. body也没有绑定,接下来找到div,这时候发现div绑定了这个事件
目标节点
  1. 找到div之后,进入到当前目标阶段,开始执行事件
冒泡阶段
  1. div执行事件结束,将事件向上传播,依次给body-html-Document,这里就是冒泡阶段

事件冒泡:IE最早提出,事件开始时由最具体的元素接收,然后主机箱上传播到DOM最顶层节点的过程

事件捕获:网景公司最早提出,有DOM最顶层节点开始,然后逐级向下传播到最具体的元素接收过程

验证

如果addEventListener第三个参数是true,那么则处于捕获阶段,执行顺序是由外向内,也就是document-html-body-target
如果addEventListener第三个参数是false或者空,那么则处于冒泡阶段,执行顺序是由内到外,也就是target-body-html-document

以下代码点击之后先弹出father框,关闭后再弹出son

<head><meta charset="UTF-8"><title>事件流</title><style>.father {width: 400px;height: 400px;margin: 200px auto;padding: 50px;background: antiquewhite;}.son {background: gray;width: 100%;height: 100%;}</style>
</head>
<body><div class="father"><div class="son">son盒子</div></div><script>// dom 事件流三阶段:// 1. JS 代码中只能执行捕获或者冒泡其中一个阶段// 2. onclick 和 attachEvent(ie)只能得到冒泡阶段// 3. 捕获阶段,如果addEventListener第三个参数是true,那么则处于捕获阶段 document-html-body-father-sonvar son = document.querySelector('.son');son.addEventListener('click',function () {alert('son');}, true);var father = document.querySelector('.father');father.addEventListener('click',function () {alert('father');}, true)</script>
</body>

以下代码点击后先弹出son框,再弹出father框,最后弹出document框。

<head><meta charset="UTF-8"><title>事件流</title><style>.father {width: 400px;height: 400px;margin: 200px auto;padding: 50px;background: antiquewhite;}.son {background: gray;width: 100%;height: 100%;}</style>
</head>
<body><div class="father"><div class="son">son盒子</div></div><script>// 4. 冒泡阶段:如果addEventListener第三个参数是false,或者省略,那么就是冒泡阶段,执行顺序 son-father-body-html-documentvar son = document.querySelector('.son');son.addEventListener('click',function () {alert('son');});var father = document.querySelector('.father');father.addEventListener('click',function () {alert('father');});document.addEventListener('click',function () {alert('document');})</script>
</body>

事件对象

  1. event 就是一个事件对象,写到侦听函数的小括号中
  2. 事件对象只有有了事件才会存在,它是系统自动创建的,无需传递参数
  3. 事件对象是事件相关的一系列相关数据的集合,跟事件相关,比如鼠标点击里面就包含了鼠标的相关信息,如果是键盘事件里面就包含了键盘的信息,比如:判断用户按下了哪个键
  4. 事件对象不一定非要写成event,名字可以随便写
  5. 事件对象也有兼容性问题,ie678通过window.event获取事件对象。

获取事件对象

传统方式获取事件对象
<body><div>一个盒子</div><script>var div = document.querySelector('div');div.onclick = function (event) {// 1. event 就是一个事件对象,写到侦听函数的小括号中// 2. 事件对象只有有了事件才会存在,它是系统自动创建的,无需传递参数// 3. 事件对象是事件相关的一系列相关数据的集合,跟时间相关,比如鼠标点击里面就包含了鼠标的相关信息,如果是键盘事件里面就包含了键盘的信息,比如:判断用户按下了哪个键console.log(event);}</script>
</body>

以上代码点击之后会在控制台输出鼠标的相关信息,如截图中所示:

在这里插入图片描述

监听方式获取事件对象

以下代码的执行顺序与上面代码无异,不做演示

<body><div>一个盒子</div><script>var div = document.querySelector('div');div.addEventListener('click',function (event) {console.log(event);})</script>
</body>
在ie678中使用监听对象
<body><div>一个盒子</div><script>var div = document.querySelector('div');div.addEventListener('click',function (event) {console.log(event); // undefinedconsole.log(window.event); // 事件对象})</script>
</body>

事件对象的常见属性和方法

事件对象属性方法说明备注
e.target返回触发事件的对象标准
e.srcElement返回触发事件的对象非标准 ie678使用
e.type返回时间的类型,比如’click’、‘mouseover’不带on
e.cancelbubble该属性组织冒泡非标准 ie678使用
e.returnValue该属性组织默认时间(默认行为)非标准 ie678使用,比如不让连接跳转
e.preventDefault()该方法阻止默认事件(默认行为)标准,比如不让链接跳转
e.stopPropagation()阻止冒泡标准
  1. this:我们给谁绑定了事件,那么this就指向谁
  2. event.target:指向我们点击的那个对象
  3. event.currentEvent类似于this,但是ie678不支持

阻止默认行为

什么是默认行为?比如a标签是跳转。

<body><a href="https://baidu.com">百度</a><script>var a = document.querySelector('a');// 1. 监听方式a.addEventListener('click',function (e) {e.preventDefault(); // DOM 标准写法})// 2. 传统方式a.onclick = function (e) {// 普通浏览器 e.preventDefault(); 方法e.preventDefault();// 低版本浏览器 ie678 returnValue 属性e.returnValue;// 也可以使用return false 阻止默认方法,没有兼容问题return false;}</script>
</body>

其中监听浏览器只能使用e.preventDefault()的写法

传统方式可以采用三种方式

  1. e.preventDefault();
  2. e.returnValue; // 仅支持 ie678
  3. return false; 最推荐的写法,没有兼容问题

阻止冒泡事件

冒泡事件:开始时由最具体的元素接收,然后主机箱上传播到DOM最顶层节点。

事件冒泡本身的特定会带来一定的好处,也会带来一定的坏处,需要我们灵活掌握。

阻止冒泡排序

  1. stopPropagation()方法

在事件方法中对事件对象使用stopPropagation()即可

在ie678中使用window.event.cancelBubble = true;的写法

事件委托

事件委托也称为事件代理,在jQuery里面成为事件委派。

不是每个子节点单独设置事件监听器,而是事件监听器设置在其父节点上,然后利用冒泡原理影响设置每个子节点。

示例

ul注册点击事件,然后利用时间对象的target来找到当前点击的li,因为点击li,事件会冒泡到ul上,ul有注册事件,就会触发事件监听器。

一起看一下以下代码:

  1. 我们给父元素ul添加点击事件,这样当我们点击子元素li之后,就会通过冒泡的方式传递到ul
  2. 我们在点击事件中通过target获取我们点击的元素,然后给它一个背景颜色
  3. 完美
<body><ul><li>弹框咯</li><li>弹框咯</li><li>弹框咯</li><li>弹框咯</li><li>弹框咯</li><li>弹框咯</li><li>弹框咯</li></ul><script>var ul = document.querySelector('ul');ul.addEventListener('click',function (e) {e.target.style.backgroundColor = 'pink';})</script>
</body>

禁用鼠标右键

<script>document.addEventListener('contextmenu',function (e) {e.preventDefault();})
</script>

注意:由于是监听事件,不支持return false;的写法,必须要用e.preventDefault();

禁用文字选择

<body><span>我是Jim.kk</span><script>document.addEventListener('selectstart',function (e) {e.preventDefault();})</script>
</body>

获取鼠标坐标信息

鼠标事件对象说明备注
e.clientX返回鼠标相对于浏览器窗口可视区的X坐标
e.clientY返回鼠标相对于浏览器窗口可视区的Y坐标
e.pageX返回鼠标相对于文档页面的X坐标IE9+ 支持
e.pageY返回鼠标相对于文档页面的Y坐标IE9+ 支持
e.screenX返回鼠标相对于电脑屏幕的X坐标
e.screenY返回鼠标相对于电脑屏幕的Y坐标
<head><meta charset="UTF-8"><title>获取鼠标坐标 </title><style>body {height: 3000px;}</style>
</head>
<body>
<script>document.addEventListener('click',function (e) {console.log(e.clientX); // 可视窗口的X坐标(纯网页部分)console.log(e.clientY); // 可视窗口的Y坐标(纯网页部分)console.log(e.pageX);   // 页面上的X坐标(若是页面发生了滚动,则该值也会增大缩小,clientX/Y不会)console.log(e.pageY);   // 页面上的X坐标(若是页面发生了滚动,则该值也会增大缩小,clientX/Y不会)console.log(e.screenX); // 当前屏幕的坐标,包含浏览器上册的操作栏部分console.log(e.screenY); // 当前屏幕的坐标,包含浏览器上册的操作栏部分})
</script>
</body>

以上代码点击后输出内容如下所示(页面已经滚动):

在这里插入图片描述

常用键盘事件

键盘事件触发条件备注
onkeyup某个按键松开时触发
onkeydown某个按键按下时触发
onkeypress某个按键按下时被触发可以区分字母大小写,但是不能识别功能键,比如:ctrl、shift、箭头等
keydown | 键盘被按下
<body>
<script>document.addEventListener('keydown',function (e) {console.log(e.key+"被按下了");})
</script>
</body>

以上代码,当我在页面上按住"s"键不放,效果如下:

在这里插入图片描述

keyup | 键盘弹起事件

与键盘按下不太一样,当键盘持续被按着时,键盘按下事件会一直被触发,但是键盘弹起事件只有在弹起的时候会被触发一次,见以下代码。

<body><script>document.addEventListener('keyup',function (e) {console.log(e.key+"弹起了");})</script>
</body>

以上代码在我点击键盘后(长按弹起后才会生效),控制台输出如下:

在这里插入图片描述

keypress | 键盘按下事件

与上面两个方法不同的是,keypress按钮对功能键不生效。

<body><script>document.addEventListener('keypress',function (e) {console.log(e.key+"被按下了");})</script>
</body>

以上代码当我在键盘上分别点击asdfctrl键后,控制台输出如下:

在这里插入图片描述

可以看到,ctrl键并没有生效。

我们可以通过event.key来获取键盘的值,或者event.keyCode来获取ASCII码值。

按下s键输入框获取焦点案例

<body><input type="text"><script>var search = document.querySelector('input');document.addEventListener('keyup',function (e) {if ( e.key === 's') {search.focus();}})</script>
</body>

以上代码用户在页面中点击s键,输入框就会获取焦点,用户就可以在输入框中输入内容了。

这篇关于【前端】前端三要素之DOM的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/731769

相关文章

Vue3 的 shallowRef 和 shallowReactive:优化性能

大家对 Vue3 的 ref 和 reactive 都很熟悉,那么对 shallowRef 和 shallowReactive 是否了解呢? 在编程和数据结构中,“shallow”(浅层)通常指对数据结构的最外层进行操作,而不递归地处理其内部或嵌套的数据。这种处理方式关注的是数据结构的第一层属性或元素,而忽略更深层次的嵌套内容。 1. 浅层与深层的对比 1.1 浅层(Shallow) 定义

这15个Vue指令,让你的项目开发爽到爆

1. V-Hotkey 仓库地址: github.com/Dafrok/v-ho… Demo: 戳这里 https://dafrok.github.io/v-hotkey 安装: npm install --save v-hotkey 这个指令可以给组件绑定一个或多个快捷键。你想要通过按下 Escape 键后隐藏某个组件,按住 Control 和回车键再显示它吗?小菜一碟: <template

【 html+css 绚丽Loading 】000046 三才归元阵

前言:哈喽,大家好,今天给大家分享html+css 绚丽Loading!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏+关注哦 💕 目录 📚一、效果📚二、信息💡1.简介:💡2.外观描述:💡3.使用方式:💡4.战斗方式:💡5.提升:💡6.传说: 📚三、源代码,上代码,可以直接复制使用🎥效果🗂️目录✍️

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

计算机毕业设计 大学志愿填报系统 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

🍊作者:计算机编程-吉哥 🍊简介:专业从事JavaWeb程序开发,微信小程序开发,定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事,生活就是快乐的。 🍊心愿:点赞 👍 收藏 ⭐评论 📝 🍅 文末获取源码联系 👇🏻 精彩专栏推荐订阅 👇🏻 不然下次找不到哟~Java毕业设计项目~热门选题推荐《1000套》 目录 1.技术选型 2.开发工具 3.功能

Vue3项目开发——新闻发布管理系统(六)

文章目录 八、首页设计开发1、页面设计2、登录访问拦截实现3、用户基本信息显示①封装用户基本信息获取接口②用户基本信息存储③用户基本信息调用④用户基本信息动态渲染 4、退出功能实现①注册点击事件②添加退出功能③数据清理 5、代码下载 八、首页设计开发 登录成功后,系统就进入了首页。接下来,也就进行首页的开发了。 1、页面设计 系统页面主要分为三部分,左侧为系统的菜单栏,右侧

【VUE】跨域问题的概念,以及解决方法。

目录 1.跨域概念 2.解决方法 2.1 配置网络请求代理 2.2 使用@CrossOrigin 注解 2.3 通过配置文件实现跨域 2.4 添加 CorsWebFilter 来解决跨域问题 1.跨域概念 跨域问题是由于浏览器实施了同源策略,该策略要求请求的域名、协议和端口必须与提供资源的服务相同。如果不相同,则需要服务器显式地允许这种跨域请求。一般在springbo

HTML提交表单给python

python 代码 from flask import Flask, request, render_template, redirect, url_forapp = Flask(__name__)@app.route('/')def form():# 渲染表单页面return render_template('./index.html')@app.route('/submit_form',

Java 后端接口入参 - 联合前端VUE 使用AES完成入参出参加密解密

加密效果: 解密后的数据就是正常数据: 后端:使用的是spring-cloud框架,在gateway模块进行操作 <dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>30.0-jre</version></dependency> 编写一个AES加密

vue2 组件通信

props + emits props:用于接收父组件传递给子组件的数据。可以定义期望从父组件接收的数据结构和类型。‘子组件不可更改该数据’emits:用于定义组件可以向父组件发出的事件。这允许父组件监听子组件的事件并作出响应。(比如数据更新) props检查属性 属性名类型描述默认值typeFunction指定 prop 应该是什么类型,如 String, Number, Boolean,