【前端】前端三要素之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键,输入框就会获取焦点,用户就可以在输入框中输入内容了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/261976.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

OpenCV人脸检测案例实战

人脸检测是一种计算机视觉技术&#xff0c;旨在识别图像或视频中的人脸。这项技术的基本内容包括使用特定的算法和模型来定位和识别人脸&#xff0c;通常涉及在图像中寻找面部特征&#xff0c;如眼睛、鼻子、嘴巴等&#xff0c;以便准确地确定人脸的位置和边界。人脸检测技术的…

MySQL 窗口函数温故知新

本文用于复习数据库窗口函数&#xff0c;希望能够温故知新&#xff0c;也希望读到这篇文章的有所收获。 本文以&#xff1a;MySQL为例 参考文档&#xff1a; https://www.begtut.com/mysql/mysql-window-functions.html 使用的样例数据&#xff1a;https://www.begtut.com/m…

9.vue学习笔记(组件传递Props校验+组件事件-组件传递数据+组件事件-配合“v-model”使用)

文章目录 1.组件传递Props校验1.1.默认值1.2.必选项1.3.注意事项&#xff1a;props 是只读的 2.组件事件-组件传递数据2.1.温馨提示&#xff1a;组件之间传递数据的方案 3.组件事件-配合“v-model”使用 1.组件传递Props校验 Vue组件可以更细致地声明对传入的 props 的校验要求…

学习鸿蒙一定要搞清楚的几个概念

目录 1、UI框架 2、应用模型 2.1、应用模型介绍 2.2、两种应用模型 2.3、应用模型和UI框架的关系 3、Ability 3.1、Ability介绍 3.2、FA模型的ability 3.3、Stage模型的Ability 1、UI框架 HarmonyOS提供了一套UI(User Interface,用户界面)开发框架&#xff0c;即方舟…

java 课程签到管理系统Myeclipse开发mysql数据库web结构jsp编程servlet计算机网页项目

一、源码特点 java 课程签到管理系统是一套完善的java web信息管理系统 采用serlvetdaobean&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发&#xff0…

OpenGauss数据库本地搭建并结合内网穿透实现远程访问

文章目录 前言1. Linux 安装 openGauss2. Linux 安装cpolar3. 创建openGauss主节点端口号公网地址4. 远程连接openGauss5. 固定连接TCP公网地址6. 固定地址连接测试 前言 openGauss是一款开源关系型数据库管理系统&#xff0c;采用木兰宽松许可证v2发行。openGauss内核深度融合…

专业140+总分420+南京信息工程大学811信号与系统考研经验南信大电子信息与通信工程,真题,大纲,参考书

今年顺利被南信大电子信息录取&#xff0c;初试420&#xff0c;专业811信号与系统140&#xff08;Jenny老师辅导班上140很多&#xff0c;真是大佬云集&#xff09;&#xff0c;今年应该是南信大电子信息最卷的一年&#xff0c;复试线比往年提高了很多&#xff0c;录取平均分380…

来分析两道小题

一、源码 二、分析 首先它会接两个参数一个是id一个是ps&#xff0c;传递的话会包含一个flag.php&#xff0c;然后数据库连接&#xff0c;之后传递过滤&#xff0c;然后查询&#xff0c;如果查到了就会取id&#xff0c;取出来看是不是跟adog一样&#xff0c;如果是它告诉你账号…

会声会影2024新功能及剪辑视频步骤教程

会声会影2024的新功能主要包括&#xff1a; 全新的标题动态与特效&#xff1a;用户可以为文字标题指定进入、中场和退出的不同动态效果&#xff0c;比如闪现进入、中场弹跳和淡出退出等&#xff0c;让文字标题更具动感。此外&#xff0c;还新增了多个标题特效&#xff0c;包括…

软考-中级-系统集成2023年综合知识(一)

&#x1f339;作者主页&#xff1a;青花锁 &#x1f339;简介&#xff1a;Java领域优质创作者&#x1f3c6;、Java微服务架构公号作者&#x1f604; &#x1f339;简历模板、学习资料、面试题库、技术互助 &#x1f339;文末获取联系方式 &#x1f4dd; 软考中级专栏回顾 专栏…

由面试题“Redis是否为单线程”引发的思考

&#x1f468;‍&#x1f393;博主简介 &#x1f3c5;云计算领域优质创作者   &#x1f3c5;华为云开发者社区专家博主   &#x1f3c5;阿里云开发者社区专家博主 &#x1f48a;交流社区&#xff1a;运维交流社区 欢迎大家的加入&#xff01; &#x1f40b; 希望大家多多支…

【大数据】Flink 之部署篇

Flink 之部署篇 1.概述和参考架构2.可重复的资源清理3.部署模式3.1 Application 模式3.2 Per-Job 模式&#xff08;已废弃&#xff09;3.3 Session 模式 Flink 是一个多用途框架&#xff0c;支持多种不同的混合部署方案。下面&#xff0c;我们将简要介绍 Flink 集群的构建模块、…

爬虫基础(下)

requests模块可以用来获取网络数据&#xff1b; 那么对于爬虫来说&#xff0c;要获取下图网页中的内容&#xff0c;就需要网页的URL。 复制链接方法是&#xff0c;打开网页&#xff0c;点击链接框&#xff0c;右键选择复制。 requests.get()函数可用于模拟浏览器请求网页的过…

Flutter 3.19.0 版本新特性

其实在每个版本的更新中呢&#xff0c;都会合并很多很多的这个合并请求、还有开发建议&#xff0c;那么本版本的也不例外&#xff0c;社区官方发布的公告是合并了168个社区成员的1429个拉请求。 当然&#xff0c;如果你的时间允许的话&#xff0c;你可以去查看一下这些请求&am…

C#,整数转为短字符串(Short string)的加解密算法与源代码

1 整数转为短字符串的应用 网站生成的动态 URL 往往以内容序列号id为标识与参数&#xff0c;比如&#xff1a; http://www.jerry.com/tom.aspx?id1 使用 Web Rewrite&#xff0c;可以实现网页静态化&#xff0c;称为&#xff1a; http://www.jerry.com/content/1.html 对…

HQYJ 2024-2-22 作业

复习前面知识点(指针、结构体、函数)&#xff08;已完成&#xff09;整理思维导图&#xff08;已完成&#xff09;顺序表(按位置插入、按位置删除和去重、重新写)理解链表的代码&#xff0c;尝试写一下链表的尾插和输出 3.顺序表(按位置插入、按位置删除和去重、重新写) 按位置…

如何使用Docker本地部署Jupyter+Notebook容器并结合内网穿透实现远程访问

文章目录 1. 选择与拉取镜像2. 创建容器3. 访问Jupyter工作台4. 远程访问Jupyter工作台4.1 内网穿透工具安装4.2 创建远程连接公网地址4.3 使用固定二级子域名地址远程访问 本文主要介绍如何在Ubuntu系统中使用Docker本地部署Jupyter Notebook&#xff0c;并结合cpolar内网穿透…

数据结构与算法之美学习笔记:53 | 算法实战(二):剖析搜索引擎背后的经典数据结构和算法

目录 前言整体系统介绍搜集1. 待爬取网页链接文件&#xff1a;links.bin2. 网页判重文件&#xff1a;bloom_filter.bin3. 原始网页存储文件&#xff1a;doc_raw.bin4. 网页链接及其编号的对应文件&#xff1a;doc_id.bin 分析索引查询总结引申 前言 本节课程思维导图&#xff1…

【GStreamer】GstElement详解:GStreamer 中最重要的对象

1、什么是元素GstElement? 每个解码器、编码器、解复用器、视频或音频输出实际上都是一个GstElement。GstElement可以视为一个黑盒子:例如,对于解码器元素,输入为已编码数据,输出为解码后的数据,解码过程已由GstElement封装好。 2、都有哪些元素GstElement? 2.1 源点…

嵌入式学习-qt-Day2

嵌入式学习-qt-Day2 一、思维导图 二、作业 1.使用手动连接&#xff0c;将登录框中的取消按钮使用qt4版本的连接到自定义的槽函数中&#xff0c;在自定义的槽函数中调用关闭函数 2.将登录按钮使用qt5版本的连接到自定义的槽函数中&#xff0c;在槽函数中判断ui界面上输入的账…