笔者最近在学习郭超老师著的《JavaScript快速入门与开发实战》,文章内容主要是本人对书本内容学习的记录。内容不是将书本内容完全复现,只记载了笔者认为较为重要或是容易遗忘的内容。02已完结。
目录
6.DOM操作
DOM操作全程文档对象模型(Document Object Model),JavaScript可以通过操作DOM接口,从而实现对HTML文档操作,包括:
- 获取HTML元素及元素内容
- 改变HTML元素的属性
- 设置HTM元素的样式
- 动态创建和删除HTML元素
- 为HTML元素绑定、解绑事件
6.1获取元素及内容
首先是获取元素的方法:
方法名 | 说明 |
document.getElementById(id) | 通过id获取元素对象,返回单个值 |
document.getElementBytagName(tagName) | 通过标签名获取元素集合,返回数组 |
document.getElementByClassName(className) | 通过类名获取元素集合,返回数组 |
document.getElementByName(name) | 通过name名获取元素,返回数组 |
document.querySelector(css 选择器) | 根据选择器返回第一个元素对象 |
document.querySelectorAll(css 选择器) | 根据选择器返回元素集合 |
6.1.1根据id获取元素
<body>
<div id="app"></div>
<script>
let divobj = document.getElementById('app');
console.log(divobj); //<div id="app"></div>
</script>
</body>
6.1.2根据标签名获取元素
<body>
<div>张三</div>
<div>李四</div>
<div>王五</div>
<script>
let divobjs = document.getElementsByTagName('div');
for(let i=0;i<divobjs.length;++i){
console.log(divobjs[i]);
}
//<div>张三</div>
//<div>李四</div>
//<div>王五</div>
</script>
</body>
6.1.3根据name获取元素
<body>
唱歌:<input type="checkbox" name="hobby">
吃饭:<input type="checkbox" name="hobby">
睡觉:<input type="checkbox" name="hobby">
写代码:<input type="checkbox" name="hobby">
<script>
let inputObjs = document.getElementsByName('hobby');
for(let i =0;i<inputObjs.length;++i){
console.log(inputObjs[i]);
}
</script>
</body>
6.1.4根据类名获取元素
<body>
<div>虚竹</div>
<div class="student">乔峰</div>
<div class="student">段誉</div>
<script>
let divObjs = document.getElementsByClassName('student');
for(let i=0;i<divObjs.length;++i){
console.log(divObjs[i]);
}
</script>
</body>
6.1.5根据选择器获取元素
<body>
<div id="app">人物集合</div>
<ul>
<li>乔峰</li>
<li>段誉</li>
</ul>
<ol>
<li>周芷若</li>
<li>赵敏</li>
</ol>
<script>
let divObj = document.querySelector('#app');
console.log(divObj);
let liObjs = document.querySelectorAll('ol li');
for(let i=0;i<liObjs.length;++i){
console.log(liObjs[i]);
}
</script>
</body>
6.1.6获取和设置元素内容操作
前面的各种方法确实获取了文档内容,但是返回的内容视乎有些多余的部分,比如返回<div>张三</div>,而我们只想要“张三”这个元素内容,这时需要使用节点对象身上的两个属性,一是innerText,二是innerHTML。
- innerText:获取标签体内容,仅仅是文本,不包含标签
- innerHTML:获取标签体内容,包含标签+文本
首先是获取元素内容
<body>
<div id="app">
<p>张三丰</p>
</div>
<script>
let divObj = document.getElementById('app');
let content1 = divObj.innerText;
console.log(content1); //张三丰
let content2 = divObj.innerHTML;
console.log(content2); //<p>张三丰</p>
</script>
</body>
然后设置元素内容:
<body>
<div id="app1"></div>
<div id="app2"></div>
<script>
let divObj1 = document.getElementById('app1');
let divObj2 = document.getElementById('app2');
divObj1.innerHTML = '<p>虚竹</p>'; //显示:虚竹 HTML内部会解析标签
divObj2.innerText = '<p>段誉</p>'; //显示:<p>段誉</p> Text内部会把标签当成普通文本
</script>
</body>
6.2属性操作
6.2.1事件属性
比如,网页上有一些按钮,用户点击后会触发某个事件,这时就需要给按钮设置事件属性。
<body>
<button>点击一下</button>
<script>
let btnObj = document.querySelector('button');
btnObj.onclick = function(){ //onclick是button的固有属性
alert('helloworld');
}
</script>
</body>
6.2.2获取内置属性
内置属性就是元素自带的属性,比如元素的id、src、title属性等。获取内置属性有两种方式:
- 元素对象.内置属性
- 元素对象.getAttribute(属性)
<body>
<div id="app">Spring</div>
<script>
let divObj = document.querySelector('div');
let value = divObj.id;
console.log(value); //app
let value1 = divObj.getAttribute('id');
console.log(value1); //app
</script>
</body>
6.2.3设置内置属性
- 元素节点.属性 = 属性值
- 元素节点.setAttribute(属性,属性值)
<body>
<div>Summer</div>
<span>Spring</span>
<script>
let divObj = document.querySelector('div');
divObj.id = 'mydiv';
let spanObj = document.querySelector('span');
spanObj.setAttribute('id','myspan');
</script>
</body>
6.2.4获取自定义属性
自定义属性就是开发者手动为元素添加的属性,只有一种获取方式。
- 元素节点getAttribute()
<body>
<div name="Spring">Spring</div>
<script>
let divObj = document.querySelector('div');
let name = divObj.name;
console.log(name); //undefined
let name1 = divObj.getAttribute('name');
console.log(name1); //Spring
</script>
</body>
6.2.5设置自定义属性
只有一种方式,即“元素节点.setAttribute(属性,属性值)”。
<body>
<div>Summer</div>
<span>Spring</span>
<script>
let divObj = document.querySelector('div');
let spanObj = document.querySelector('span');
divObj.name = 'helloworld';
console.log(divObj.name); //输出了 helloworld 但是这里的name并非HTML特性
spanObj.setAttribute('name','javascript');
</script>
</body>
6.2.6H5自定义属性的规范
为了更好的区分属性到底是自定义的还是内置的,H5提出了规范,即所有的自定义属性都以“data-”开头。设置自定义属性,需要使用“元素节点.setAttribute(属性,属性值)”的方式。
<body>
<div>Summer</div>
<script>
let divObj = document.querySelector('div');
divObj.setAttribute('data-name','helloworld');
</script>
</body>
获取自定义属性的方式有两种:
- 元素节点.getAttribute(属性)
- 元素节点.dataset.属性,部分浏览器不支持。
<body>
<div data-name="helloworld">Summer</div>
<script>
let divObj = document.querySelector('div');
let r1 = divObj.getAttribute('data-name');
console.log(r1);
let r2 = divObj.dataset.name;
console.log(r2);
</script>
</body>
6.2.7移除属性
不论是自定义属性还是内置属性,都使用“元素节点.removeAttribute(属性名)”的方式。
<body>
<div id="summer" data-name="helloworld">Summer</div>
<script>
let divObj = document.querySelector('div');
divObj.removeAttribute('id');
divObj.removeAttribute('data-name');
</script>
</body>
6.2.8表单属性
表单节点也是重点学习内容,用于获取用户输入的信息,value属性非常重要。
<body>
用户名:<input type="text" name="username">
简介:<textarea name="" id=""></textarea>
<button>获取表单控件的值</button>
<script>
let btnObj = document.querySelector('button');
btnObj.onclick = function(){
//获取用户名文本框的值
let inputObj = document.getElementsByName('username')[0];
console.log(inputObj.value);
//获取文本域的值
let textAreaObj = document.querySelector('textarea');
console.log(textAreaObj.value);
}
</script>
</body>
6.3样式操作
样式操作即CSS-DOM,可以通过JavaScript去改变元素的样式,比如宽高、颜色、边距等。有两种操作方式:
- 元素节点.style
- 元素节点.className
6.3.1行内样式操作
通过“元素节点.style”修改样式属于行内样式,意味着CSS权重更高,同时注意,当需要使用中间带有“-”的CSS属性时,需要使用驼峰法命名或使用“[ ]”的方式(本质是获取对象身上的属性).
<body>
<div>helloworld</div>
<button>设置div的样式</button>
<script>
let btnObj = document.querySelector('button');
btnObj.onclick = function(){
//获取div节点
let divObj = document.querySelector('div');
//设置样式
divObj.style.color = 'red';
// >>驼峰法
divObj.style.backgroundColor = 'gray';
// >>[]方式,获取对象的属性
divObj.style['font-size'] = '60px';
divObj.style['width'] = '400px';
divObj.style.height = '400px';
}
</script>
</body>
6.3.2类名样式操作
对于行修改行类样式的写法,如过要修改多个样式,编写时很麻烦,因此可以通过类名的统一修改。
写法本身应该是“元素节点.class”,但是class是一个关键字,此时改为“className”来操作。
<head>
<style>
.myStyle{
width: 300px;
height: 300px;
background-color: bisque;
}
</style>
</head>
<body>
<div>helloworld</div>
<div>javascript</div>
<button>通过类名修改div样式</button>
<script>
let btnObj = document.querySelector('button');
btnObj.onclick = function(){
let divObj = document.querySelectorAll('div');
divObj.forEach(div=>{
div.className='myStyle';
});
}
</script>
</body>
同时注意,通过类名方式修改样式,会把原来的class样式覆盖掉,如果需要保留原样式,修改时把原样式附加上。
<body>
<div class="style1">helloworld</div>
<div>javascript</div>
<button>通过类名修改div样式</button>
<script>
let btnObj = document.querySelector('button');
btnObj.onclick = function(){
let divObj = document.querySelector('div');
divObj.className='style1 myStyle';
}
</script>
</body>
6.4节点操作
DOM文档模型是一颗倒立的树状结构,每一部分都是节点,用node表示,当然就有子节点和父节点,也有平级的节点,如兄弟节点,一个子节点只有一个父节点,但可以有多个子节点。
节点类型 | nodeType | nodeName | nodeValue |
文档(documen) | 9 | #document | null |
元素(Element) | 1 | 标签名称 | null |
属性(Attr) | 2 | 属性名称 | 属性值 |
文本(Text) | 3 | #text | 文本内容 |
注释(Comment) | 8 | #comment | 注释文本本身 |
6.4.1获取父节点
通过“元素节点.parentNode”实现,只会返回唯一的父节点,没有则返回null。
<body>
<div>
<a href="">bing</a>
</div>
<script>
let aObj = document.querySelector('a');
let divObj = aObj.parentNode;
console.log(divObj);
</script>
</body>
6.4.2获取子节点
有两种方式:
- 元素节点.childNodes,返回子节点数组,会包含空白的文本节点
- 元素节点.children,只返回子元素节点,部分浏览器不支持
<body>
<ol>
<li>周芷若</li>
<li>张三丰</li>
<li>虚竹</li>
</ol>
<button>获取ol下所有的li内容</button>
<script>
// “元素节点.childNodes”
let btnObj = document.querySelector('button');
btnObj.onclick = function(){
let olObj = document.querySelector('ol');
let childNodes = olObj.childNodes;
for(let i=0;i<childNodes.length;++i){
if(childNodes[i].nodeType === 1){
console.log(childNodes[i].innerText);//周芷若 张三丰 虚竹
}
}
}
</script>
</body>
<body>
<ol>
<li>周芷若</li>
<li>张三丰</li>
<li>虚竹</li>
</ol>
<button>获取ol下所有的li内容</button>
<script>
// “元素节点.children”,会忽略文本节点
let btnObj = document.querySelector('button');
btnObj.onclick = function(){
let olObj = document.querySelector('ol');
let childNodes = olObj.children;
console.log(childNodes); //[li,li,li]
}
</script>
</body>
6.4.3获取兄弟节点
一个节点可能有多个兄弟节点,这里的获取兄的节点不是获取所有的节点,而是获取前一个和后一个兄弟节点,同时和上一节相似,不同的方法获取的兄弟节点是一个空白节点还是元素节点。
<body>
<div>张三丰</div>
<p>乔峰</p>
<h1>虚竹</h1>
<script>
let pObj = document.querySelector('p');
//获取p节点的前一个兄弟节点,是一个空白的文本节点
console.log(pObj.previousSibling);
//获取p节点的前一个兄弟节点,是div元素节点
console.log(pObj.previousElementSibling);
</script>
</body>
两者区别在于:
- previousSibling,它获取的是前一个兄弟节点,这里的兄弟节点可以是任意类型的节点,像元素节点、文本节点、注释节点等都包含在内。
- previousElementSibling,此方法获取的前一个兄弟节点限定为元素节点,会自动跳过文本节点、注释节点等其他类型的节点。
6.4.4创建及添加节点
方法:“Document.createElement(标签名)”,属于动态创建节点,创建的节点在文档上并不存在,需要结合“appendChild()”或者"insertBefore()",将创建好的节点添加到指定的元素节点中。
<body>
<ul>
<li>张三</li>
</ul>
<script>
//获取ul元素节点
let ulObj = document.querySelector('ul');
//创建指定的li元素节点
let liObj = document.createElement('li');
liObj.innerHTML = '李四';
//通过appendChild方法 追加到ul节点的末尾
ulObj.appendChild(liObj);
//创建元素节点
let liObj2 = document.createElement('li');
liObj2.innerHTML = '王五';
//通过insetBefore 方法添加li节点到ul节点的第一个节点之前
ulObj.insertBefore(liObj2,ulObj.children[0]);
</script>
</body>
6.4.5删除节点
通过“元素节点.removeChild()”,将当前元素节点的下的某个节点删除;通过“元素节点.remove()”,可以将当前的元素节点删除。
<body>
<ul>
<li>张三</li>
<li>李四</li>
<li>王五</li>
</ul>
<button id="one">删除ul下的第一个li</button>
<button id="two">删除ul下的最后一个li</button>
<script>
//获取ul元素节点
let ulObj = document.querySelector('ul');
let btnObj1 = document.querySelector('#one');
btnObj1.onclick = function(){
// >>removeChild()通过父节点删除某个具体的子节点
ulObj.removeChild(ulObj.firstElementChild);
}
let btnObj2 = document.querySelector('#two');
btnObj2.onclick = function(){
// >>remove() 把当前节点删除
ulObj.lastElementChild.remove();
}
</script>
</body>
6.4.6复制节点
通过“元素节点.cloneNode()”。该方法如果不接受参数或者参数为false,则为浅复制,只会复制节点本身,不会复制其子节点;如果接收一个true参数,则是深复制,不仅复制当前节点,还会复制其子节点。
<body>
<div>
<p>张三</p>
</div>
<script>
//浅复制
let divObjCopy = document.querySelector('div').cloneNode();
document.querySelector('body').appendChild(divObjCopy);
//此时在控制台中可以看到script标签下出现了一个div标签,并且内容为空
</script>
</body>
<body>
<div>
<p>张三</p>
</div>
<script>
//深复制
let divObjCopy = document.querySelector('div').cloneNode(true);
document.querySelector('body').appendChild(divObjCopy);
//此时在控制台中可以看到script标签下出现了一个div标签,并且内容为“张三”
</script>
</body>
6.4.7创建及设置属性节点
通过“document.createAttribute()”,可以创建属性节点并赋值,属性节点创建好后,需要设置到具体的元素节点上。
<body>
<div>
张三
</div>
<script>
let divObj = document.querySelector('div');
//创建username属性
let attr = document.createAttribute('username');
//为username属性设置为“zhangsan”
attr.value = 'zhangsan';
//为div元素节点设置属性节点
divObj.setAttributeNode(attr);
</script>
</body>
6.5 DOM事件
简单来说,用户在页面上的某个操作触发了某个事件。比如,用户点击按钮、移动鼠标、按下键盘等操作都称为事件,事件处理通常是一个函数。
6.5.1注册事件
给元素添加事件,叫做注册事件。注册事件有两种形式:一种通过动态绑定事件的方式,另一种通过实践监听注册的方式。
动态绑定事件:元素对象.事件 = 事件处理程序
<body>
<button>点击我</button>
<script>
let btnObj = document.querySelector('button');
btnObj.onclick = function(){
console.log('helloworld');
}
btnObj.onclick = function(){ //后者会覆盖前者
console.log('spring');
}
</script>
</body>
事件监听注册:元素对象.addEventListener(事件类型,事件处理函数,布尔值)
这里的布尔值如果为true则是事件捕获阶段,如果为false或空值,则为事件冒泡阶段,后续会学习事件发生阶段
<body>
<button>点击我</button>
<script>
let btnObj = document.querySelector('button');
btnObj.addEventListener('click',function(){ //这里的click不能是关键字
console.log('helloworld');
})
btnObj.addEventListener('click',function(){ //不会覆盖前者,程序会依次执行
console.log('spring');
})
</script>
</body>
6.5.2删除事件
删除事件也叫解绑事件,由于注册事件有两种方式,则删除事件也有两种。
- 若采取动态绑定事件,则移除时:元素对象.事件=null
- 若采取事件监听,则移除时:元素对象.removeEventListener()
动态绑定并移除:
<body>
<button id="one">按钮1</button>
<button id="two">按钮2</button>
<script>
//为按钮1绑定事件
let btnObj1 = document.querySelector('#one');
btnObj1.onclick = function(){
console.log('按钮1的事件');
}
//为按钮2绑定事件,目的是把按钮1的事件删除
let btnObj2 = document.querySelector('#two');
btnObj2.onclick = function(){
btnObj1.onclick=null;
}
</script>
</body>
事件监听注册移除:
<body>
<button id="one">按钮1</button>
<button id="two">按钮2</button>
<script>
function fn1(){
console.log('按钮1被点击了');
}
function fn2(){
console.log('按钮1又被点击了.....');
}
//为按钮1绑定点击事件,分别为fn1和fn2
let btnObj1 = document.querySelector('#one');
btnObj1.addEventListener('click',fn1);
btnObj1.addEventListener('click',fn2);
//为按钮2绑定事件,作用是吧按钮1的fn1事件删除
let btnObj2 = document.querySelector('#two');
btnObj2.onclick = function(){
btnObj1.removeEventListener('click',fn1);
}
</script>
</body>
6.5.3事件流
类比程序/代码执行的过程,事件流就是页面中接收事件的顺序。当事件发生时,事件会在元素节点域根节点之间按照特定的顺序传播,传播的路径所经过的节点都会接收到该事件,这个传播过程叫做DOM事件流。
事件传播顺序对应了浏览器的事件流模型,有两种,分别是:
- 捕获事件模型:从父节点到子节点的传播
- 冒泡事件模型:从子节点到父节点的传播
举个例子: 1.Document 2.Element html 3.Element Body 4.Element div
捕获事件顺序:1 -> 4
冒泡事件顺序:4 -> 1
上面介绍了两种事件流,而DOM有一种标准事件流,一般采用“捕获+冒泡”。从Document开始,最后回到Document。
DOM标准事件流包括三个阶段,分别是:
- 事件捕获阶段,实际目标“div”在捕获阶段不会接收事件,事件从“document”到“html”再到“body”结束。
- 处于当前目标阶段,事件在实际目标“div”上被处理,实际上事件处理会被看作成冒泡阶段的一部分。
- 事件冒泡阶段,事件在实际目标发生后,逐层向上沿着节点传递,最终至“document”节点。
关于JavaScript对于事件冒泡的详细做法,示例代码如下:
<body>
<div id="one" class="one">
点击我 - 外层 (one)
<div id="two" class="two">
点击我 - 中层 (two)
<div id="three" class="three">
点击我 - 内层 (three)
</div>
</div>
</div>
</body>
<script>
let divObj1 = document.querySelector('#one');
divObj1.addEventListener('click',function(){
alert('one');
});
let divObj2 = document.querySelector('#two');
divObj2.addEventListener('click',function(event){
alert('two');
});
let divObj3 = document.querySelector('#three');
divObj3.addEventListener('click',function(event){
alert('three');
});
</script>
上述代码所实现的功能可通过点击各层来实现。比如点击外层(one)会提示“one”,点击中层(two)会依次提示“two”->“one”,点击内层(three)会依次提示“three”->"two"->"one"。事件冒泡的顺序为从内到外。
关于JavaScript对于事件捕获的详细做法,实例代码如下:
<body>
<div id="one" class="one">
点击我 - 外层 (one)
<div id="two" class="two">
点击我 - 中层 (two)
</div>
</div>
</body>
<script>
let divObj1 = document.querySelector('#one');
divObj1.addEventListener('click',function(){
alert('one');
},true);
let divObj2 = document.querySelector('#two');
divObj2.addEventListener('click',function(event){
alert('two');
},true);
</script>
事件捕获的顺序是从外到内,比如,点击中层,会首先提示“one”再提示“two”。和事件冒泡顺序相反。
写道这里时,笔者突发奇想,如果只给部分的事件监听器设置“true”属性,会产生什么效果呢?
<script>
let divObj1 = document.querySelector('#one');
divObj1.addEventListener('click',function(){
alert('one');
});
let divObj2 = document.querySelector('#two');
divObj2.addEventListener('click',function(event){
alert('two');
},true);
let divObj3 = document.querySelector('#three');
divObj3.addEventListener('click',function(event){
alert('three');
});
</script>
这里只给第二个“div”设置“true”属性,下面来看看效果。
首先点击外层,只会提示“one”,然后点击中层,会依次提示“two”->"one",最后点击内层,会依次提示“two”->"three'->"one"。
那么原因是什么?先回顾下标准事件流,捕获->事件处理->冒泡,正常情况下在捕获阶段不会处理事件,但是可以人为设计让其在这个阶段处理事件,也就是增加一个“true”属性,当我们点击中层时,程序在捕获阶段依次经过外层和中层,外层没有“true”属性,会被忽略,而中层有“true”属性,会被优先处理,最后冒泡返回到外层,并处理外层的事件,因此会依次提示“two”->"one"。
同理,当我们点击内层时,程序在捕获阶段经过中层时先处理其事件,弹出提示信息,在冒泡阶段原路返回,依次处理内层和外层的事件,最终会依次弹出“two”->"three"->"one"。
最后稍微总结一下:
- 事件流就是JavaScript中代码的执行顺序,默认情况是捕获->事件处理->冒泡,事件处理可以看作冒泡的开头。
- 动态绑定事件可以通过参数来控制其是冒泡还是捕获,例如 “
addEventListener
” 方法,该方法接收三个参数,分别是事件类型(字符串)、事件处理函数、布尔值(可省略)。当将第三个参数设置为true
时,程序会将该事件看作在捕获阶段处理的事件;如果不设置或设置为false
,则默认为在冒泡阶段处理的事件。 - 并不是所有的事件都有冒泡阶段,例如 onfocus、onblur。
6.5.4事件对象
事件对象用来记录事件发生时的相关信息,代表了事件的状态,在JavaScript中,事件对象就是“event”。
事件对象有些注意事项:
- 事件发生时,浏览器才会创建事件对象,不需要开发者创建,并且事件对象只能在相应的程序内访问,事件执行完后,事件对象自动销毁;
- 事件对象的访问,对于大部分浏览器,只需要在函数的形参中定义 event 参数即可,对于早期的浏览器,需要通过“window.event”去获取;
- 考虑兼容性问题,要获取event对象,写法为:“event = event || window.event”;
获取事件对象,实例代码如下:
<body>
<div class="container">
天气不错
</div>
</body>
<script>
let divObj = document.querySelector('div');
//传统方式绑定事件
divObj.onclick = function(event){
event = event || window.event;
console.log(event);
}
//方法监听方式绑定
divObj.addEventListener('click',function(event){
console.log(event);
});
</script>
鼠标点击div的区域,可以在控制台中看到 PointerEvent 事件对象。
6.5.5阻止事件冒泡
事件发生时,有时候不想触发某些元素,但是由于事件冒泡的性质,导致不需要触发的元素节点触发了,解决这个问题,通常使用“event.stopPropagation”实现,实例代码如下。
<body>
<div id="one" class="one">
one
<div id="two" class="two">
two
<div id="three" class="three">
three
</div>
</div>
</div>
</body>
<script>
let divObj1 = document.querySelector('#one');
let divObj2 = document.querySelector('#two');
let divObj3 = document.querySelector('#three');
divObj1.addEventListener('click',function(){
alert('one');
})
divObj3.addEventListener('click',function(){
alert('three');
})
//阻止事件冒泡
divObj2.addEventListener('click',function(){
alert('two');
event.stopPropagation();
})
</script>
点击上图的three 区域,按照之前学习的事件流顺序,会依次提示信息 three->two->one,但是代码中在two事件中加入了一个event.stopPropagation(),事件在冒泡时会被截断,点击three区域,最后会提示信息 three->two。
6.5.6阻止事件默认行为
对于一些元素来说,都会有一些默认属性,比如超链接的默认行为是跳转,表单的“submit”按钮默认行为是提交表单,这些行为在某些时候需要取消或屏蔽,通常采用“event.preventDefault”实现。下面以阻止超链接和表单提交的默认行为为例。
阻止超链接的默认行为,有三种方式:
- 设置超链接的 href 属性值为“javascript:void(0)”;
- 通过"event.preventDefault()"方式;
- 通过“return false”方式,注意,此方法只适用于动态绑定,不适用于事件监听。
实例代码如下:
<body>
<a href="https://www.baidu.com">百度</a>
</body>
<script>
let aObj = document.querySelector('a');
aObj.addEventListener('click',function(event){
alert('点击了,但不会跳转');
event.preventDefault();
})
</script>
<body>
<a href="https://www.baidu.com">百度</a>
</body>
<script>
let aObj = document.querySelector('a');
aObj.onclick = function(){
alert('点击了,但不会跳转');
return false;
}
</script>
<body>
<a href="javascript:void(0)">百度</a>
</body>
阻止表单的默认行为,有两种方法:
- 对于事件监听,使用“event.preventDefault()”;
- 对于动态绑定,使用“return false”;
示例代码如下:
<body>
<form action="https://www.baidu.com">
用户名:<input type="text"> <br>
<input type="submit" value="提交">
</form>
</body>
<script>
let btnObj = document.querySelector('input[type=submit]');
btnObj.addEventListener('click',function(event){
alert('提交了表单,但不会接收');
event.preventDefault();
})
</script>
<body>
<form action="https://www.baidu.com">
用户名:<input type="text"> <br>
<input type="submit" value="提交">
</form>
</body>
<script>
let btnObj = document.querySelector('input[type=submit]');
btnObj.onclick = function(){
alert('提交了表单,但不会提交');
return false;
}
</script>
6.5.7事件委派
事件委派是指将事件统一注册到子元素共同的父元素(或祖元素)上,当子元素上触发事件时,利用事件冒泡机制,事件会传播到父元素,进而通过父元素去执行。下面看一个案例。
首先页面上有三个“li”节点,要求输出每个“li”节点的内容。
不使用事件委派:
<body>
<ul>
<li>111</li>
<li>222</li>
<li>333</li>
</ul>
</body>
<script>
let liObj = document.querySelectorAll('li');
for(let i = 0; i <liObj.length ; ++i){
liObj[i].addEventListener('click',function(){
let content = this.innerText;
console.log(content);
})
};
</script>
使用事件委派:
<body>
<ul>
<li>111</li>
<li>222</li>
<li>333</li>
</ul>
</body>
<script>
let ulObj = document.querySelector('ul');
ulObj.addEventListener('click',function(event){
//event.target获取的是谁触发了这个事件,这里是li节点触发的
//这里不能使用this,this指向的是ul
let content = event.target.innerText;
console.log(content);
})
</script>
事件委派的好处:
- 原本应该在子元素上绑定事件执行相应的功能,而利用了事件冒泡,把事件绑定在了父元素上,这里只需要绑定一次,如果不这样做,设想有100各“li”节点,那就需要绑定100次,明显前者效率更高;
- 对于动态生成的元素节点,即便元素是事后添加的,使用动态绑定(如
createElement
、appendChild
等方法)事件和事件监听(如addEventListener)都不能为这样的元素注册事件,必须使用事件委派; - 还要注意的是,事件委派中应该使用“event.target”来获取触发事件的元素,不同于以往使用的“this”。
6.5.8窗口事件
由窗口window节点对象触发的事件,常见的用法如下:
事件 | 说明 |
onload | 整个文档加载完毕之后触发,包括图片,css文件等资源 |
DOMContentLoaded | DOM加载完成就触发,不必等待图片、css文件等资源加载 |
onresize | 当窗口大小发生改变时触发 |
案例1:当整个文档加载完毕,在控制台输出节点内容。
<body>
<div>helloworld</div>
</body>
<script>
window.onload = function(){
let divObj = document.querySelector('div');
console.log(divObj.innerText);
}
</script>
这里有些需要注意的事项,在JavaScript中,代码是从上到下依次执行的,如果把“script”代码放在“body”之上,并且没有使用onload属性,那么是无法获取到目标元素的内容的。
案例2:当窗口宽度小于“1000px”时,将div隐藏。
<body>
<div>helloworld</div>
</body>
<script>
let divObj = document.querySelector('div');
window.onresize = function(){
if(window.innerWidth<1000){
divObj.style.display = 'none';
}
}
</script>
6.5.9鼠标事件
当用户鼠标移动或点击时产生的事件,常见用法如下:
事件 | 说明 |
onclick | 鼠标点击时触发 |
onmousemove | 移动时触发 |
onmouseover | 鼠标移入时产生事件冒泡 |
onmouseout | 鼠标移出时产生事件冒泡 |
onmouseenter | 鼠标移入时不产生事件冒泡 |
onmouseleave | 鼠标移出时不产生事件冒泡 |
onmousedown | 当鼠标按下时触发 |
onmouseup | 当鼠标弹起时触发 |
contextmenu | 捕获用户的右键操作 |
selectstart | 鼠标开始选择文字时触发 |
案例1:自定义右键菜单,在文档中鼠标右击,展示一个无序列表
<style>
ul{
list-style :none;
position: absolute;
width: 80px;
display: none;
}
</style>
<body>
<ul>
<li>html</li>
<li>css</li>
</ul>
</body>
<script>
let ulObj = document.querySelector('ul');
document.addEventListener('contextmenu',function(event){
//1.首先禁用右键菜单,阻止其默认行为
event.preventDefault();
//2.展示自定义菜单
ulObj.style.left = event.pageX + 'px';
ulObj.style.top = event.pageY + 'px';
ulObj.style.display = 'block';
});
</script>
案例2:对于文档中的文字,禁止鼠标选中
<body>
<div>helloworld</div>
</body>
<script>
let divObj = document.querySelector('div');
divObj.addEventListener('selectstart',function(event){
event.preventDefault();
})
</script>
6.5.10键盘事件
指通过键盘触发的事件,通常和文本输入框搭配,常见用法如下:
事件 | 说明 |
onkeydown | 当按下键盘时触发 |
onkeyup | 当松开键盘时触发 |
onkeypress | 当键盘按下可打印的字符时触发(shift,alt,ctrl,等不触发) |
案例1:一边在文本框输入内容,一边将文本框的内容显示在页面上
<body>
<div></div>
<input type="text">
</body>
<script>
let inputObj = document.querySelector('input');
inputObj.addEventListener('keyup',function(event){
let content = event.target.value;
document.querySelector('div').innerText = content;
})
</script>
案例2:判断用户是否按下了“b”键,输出“是”或“否”
<script>
document.addEventListener('keydown',function(event){
if(event.keyCode === 66){
document.write('是');
}else{
document.write('否');
}
})
</script>
6.5.11表单事件
常见用法如下:
事件 | 说明 |
onblur | 元素失去焦点时触发 |
onfocus | 元素获取焦点时触发 |
onchange | 元素值发生改变时触发 |
oninput | 元素获得用户输入时触发 |
onsubmit | 提交表单时触发 |
案例1:当文本框获取焦点,文本框背景为红色,否则,文本框背景为蓝色
<body>
输入:<input type="text">
</body>
<script>
let inputObj = document.querySelector('input');
inputObj.onfocus = function(){
this.style.backgroundColor = 'red';
}
inputObj.onblur = function(){
this.style.backgroundColor = 'blue';
}
</script>
案例2:用户在文本框输入内容,内容在页面上同步显示
<body>
<div></div>
输入:<input type="text">
</body>
<script>
let inputObj = document.querySelector('input');
inputObj.oninput = function(){
document.querySelector('div').innerText = this.value;
}
</script>
案例3:当下拉选择框的值切换时,在控制台输出切换后的值
<body>
<select>
<option value="北京市">北京市</option>
<option value="天津市">天津市</option>
<option value="郑州市">郑州市</option>
</select>
</body>
<script>
let selectObj = document.querySelector('select');
selectObj.onchange = function(){
console.log(this.value);
}
</script>
6.6经典案例
6.6.1简易版新闻评论
用户在文本域输入评论内容,点击“评论”按钮,将评论追加到“ul”节点中。
<body>
新闻评论:<textarea name="" id="" cols="" rows=""></textarea> <br>
<ul></ul>
<button>评论</button>
</body>
<script>
let btnObj = document.querySelector('button');
btnObj.onclick = function(){
//1.获取textarea的内容
let content = document.querySelector('textarea').value;
//2.创建‘li’节点
let liObj = document.createElement('li');
//3.为li节点设置内容
liObj.innerText = content;
//4.获取‘ul’节点
let ulObj = document.querySelector('ul');
//5.将‘li’添加到‘ul’节点中
ulObj.appendChild(liObj);
}
</script>
6.6.2稍微复杂版新闻评论
在上个案例的基础上,实现节点的删除操作,例如,添加一条评论之后,在对应的评论后提供删除超链接,以实现对该评论的删除。
<body>
新闻评论:<textarea name="" id="" cols="" rows=""></textarea> <br>
<ul></ul>
<button>评论</button>
</body>
<script>
let btnObj = document.querySelector('button');
btnObj.onclick = function(){
//1.获取textarea的内容
let content = document.querySelector('textarea').value;
//2.创建‘li’节点
let liObj = document.createElement('li');
//3.为li节点设置内容
liObj.innerText = content + ' ';
//4.创建删除超链接节点并绑定点击事件
let aObj = document.createElement('a');
aObj.setAttribute('href','#');
aObj.innerText = '删除';
aObj.onclick = function(event){
event.preventDefault();
//this.parentNode指 li this.parentNode.parentNode指 ul
this.parentNode.parentNode.removeChild(this.parentNode);
}
liObj.appendChild(aObj);
//5.获取‘ul’节点
let ulObj = document.querySelector('ul');
//6.将‘li’添加到‘ul’节点中
ulObj.appendChild(liObj);
}
</script>
思路分析:每点击评论按钮,发表评论,在创建li节点的同时,直接创建与li节点对应的删除超链接节点,同时为删除超链接节点绑定点击事件,当点击删除超链接时触发点击事件,还要去阻止超链接默认的行为。
针对上述案例,是否还有一种更简单的方式呢?代码如下:
<body>
新闻评论:<textarea name="" id="" cols="" rows=""></textarea> <br>
<ul></ul>
<button>评论</button>
</body>
<script>
let btnObj = document.querySelector('button');
btnObj.onclick = function(){
//1.获取textarea的内容
let content = document.querySelector('textarea').value;
//2.创建‘li’节点
let liObj = document.createElement('li');
//3.为li节点设置内容
liObj.innerHTML = content + ' ' + '<a href="javascript:void(0)">删除</a>' ;
//4.获取‘ul’节点
let ulObj = document.querySelector('ul');
//6.将‘li’添加到‘ul’节点中
ulObj.appendChild(liObj);
}
//利用事件委托,给ul绑定点击事件,完成对超链接的触发动作
let ulObj = document.querySelector('ul');
ulObj.addEventListener('click',function(event){
//获取触发事件的目标元素,就是删除超链接
let target = event.target;
//通过ul节点删除超链接的父节点,即li节点
ulObj.removeChild(target.parentNode);
})
//当事件发生时(如点击、鼠标移动等),event.target 会返回触发该事件的最具体的元素。无论事件监听器绑定在哪个元素上,event.target 始终指向事件的源头。
</script>
这里要注意的是,不能直接给超链接绑定点击事件,因为超链接的生成是点击了评论按钮之后才动态生成的,这样是不能直接获取到超链接节点的,需要通过事件委托。
6.6.3全选案例
页面上有一个全选复选框和多个爱好复选框,实现点击全选复选框将所有的爱好选中;同时点击每个爱好,当所有的爱好都被选中时,全选复选框也被选中。示例代码如下:
<body>
全选:<input type="checkbox" id="selectAll"> <br>
爱好:唱歌:<input type="checkbox" name="hobby">
跳舞:<input type="checkbox" name="hobby">
吃饭:<input type="checkbox" name="hobby">
睡觉:<input type="checkbox" name="hobby">
</body>
<script>
let selectAllObj = document.querySelector('#selectAll');
let hobbyObjs = document.querySelectorAll('input[name=hobby]');
selectAllObj.addEventListener('click',function(){
//1.获取全选框状态
let checked = this.checked;
//2.根据全选复选框的状态设置每一个爱好的状态
for(let i=0;i<hobbyObjs.length;++i){
hobbyObjs[i].checked = checked;
}
})
//为每个爱好复选框绑定点击事件
for(let i=0;i<hobbyObjs.length;++i){
hobbyObjs[i].addEventListener('click',function(){
//假设全选复选框是被勾上的
let flag = true;
for(let k=0;k<hobbyObjs.length;++k){
if(!hobbyObjs[k].checked){
flag=false;
break;
}
}
//统一设置全选复选框的状态
selectAllObj.checked = flag;
})
}
</script>
首先对全选设置一个点击函数,点击全选后,函数中会遍历所有的 hobby 元素,并将其确认状态和全选的确认状态同步;然后通过确认每个单选元素,如果其中有一个没有被选上,那么就会撤销全选的确认状态。
6.6.4隔行变色案例
页面上有个无序列表,当鼠标移入每一行时设置背景色为红色,移除后恢复为原来的背景色。示例代码如下:
<body>
<ul>
<li>111</li>
<li>222</li>
<li>333</li>
<li>444</li>
<li>555</li>
<li>666</li>
</ul>
</body>
<script>
let liObj = document.querySelectorAll('li');
for(let i=0;i<liObj.length;++i){
//为每个li绑定移入事件
liObj[i].addEventListener('mouseover',function(){
this.style.backgroundColor = 'red';
});
//为每个li绑定移出事件
liObj[i].addEventListener('mouseout',function(){
this.style.backgroundColor = '';
});
}
</script>
7.BOM操作
BOM全称为浏览器对象模型(Browser Object Model),提供了独立于内容而与浏览器窗口进行交互的对象。意味着BOM不参与文档内容的操作,仅仅与浏览器窗口进行交互。
常见的BOM对象如下:
- window:代表着整个浏览器窗口,同时window也是网页中的全局对象,也是核心对象;
- location:代表着当前浏览器地址栏的信息,通过该对象可以完成页面跳转、刷新等功能;
- history:代表浏览器的历史记录,可以实现浏览器的前进和后退;
- navigatior:代表浏览器的信息,可以用来识别不同的浏览器;
7.1window对象
window是顶级窗口对象,使用时不需要创建,使用时也可省略,比如使用“alert()”方法弹出警告框,同时要注意,window对象是一个全局对象,定义在全局作用域中的变量、函数都会成为window对象身上的属性和方法。并且,DOM中的document对象实际上也是window对象的一个属性。
在全局定义变量和函数会作为window对象的属性和方法,示例代码如下:
<script>
var age = 30;
console.log(age);
console.log(window.age);
function info(){
console.log('info--');
}
info();
window.info();
</script>
7.1.1警告框
语法:window.alert(),window可省略不写。
7.1.2确认框
语法window.confirm(确认提示信息)。
该方法弹出一个对话框,包含一个确认按钮和一个取消按钮,点击确认则会返回true,否则返回false。该方法使用场景是当用户要做删除操作时,能够给用户再次选择的机会,示例代码如下:
<body>
<ul>
<li>111</li>
<li>222</li>
<li>333</li>
<li>444</li>
</ul>
</body>
<script>
let liObjs = document.querySelectorAll('li');
let ulObj = document.querySelector('ul');
for(let i=0;i<liObjs.length;++i){
liObjs[i].innerHTML += ' ' + '<a href="javascript:void(0)">删除</a>'
}
ulObj.addEventListener('click',function(event){
let target = event.target;
let result = window.confirm('是否要删除图书?');
if(result){
ulObj.removeChild(target.parentNode);
return ;
}else{
alert('您取消了删除操作。')
}
})
</script>
7.1.3提示框
语法:window.prompt(提示内容)
弹出一个对话框,有一个输入框可以用来接收用户的输入,该方法返回一个字符串。
从键盘上输入两个整数,实现两个整数相加,示例代码如下:
<script>
let num1 = window.prompt('输入第一个整数:');
let num2 = window.prompt('输入第二个整数:');
let res = parseInt(num1) + parseInt(num2);
console.log(res);
</script>
7.1.4打开窗口
语法:window.open(url,name)
作用:在新的window或新的tab页打开一个页面。
在网页中点击按钮,会在新窗口打开百度网页,示例代码如下:
<body>
<button>打开百度</button>
</body>
<script>
let btnObj = document.querySelector('button');
btnObj.addEventListener('click',function(){
window.open('https://www.baidu.com');
})
</script>
7.1.5关闭窗口
语法:window.close()
作用:关闭浏览器窗口。
点击按钮,关闭当前页面,示例代码如下:
<body>
<button>关闭窗口</button>
</body>
<script>
let btnObj = document.querySelector('button');
btnObj.addEventListener('click',function(){
window.close();
})
</script>
7.2 location对象
location对象封装了浏览器的地址栏信息,也就是当前url的信息。
7.2.1重新加载页面
语法:window.location.reload(布尔值)
用来刷新页面,同时会清空缓存,接收参数“true”表示强制刷新,示例代码如下:
<body>
<button>刷新窗口</button>
</body>
<script>
let btnObj = document.querySelector('button');
btnObj.addEventListener('click',function(){
window.location.reload();
})
</script>
7.2.2跳转其他页面
语法:window.location.assign(网址)
该方法在原网页上打开一个新的网页,会产生访问记录,可以进行前进后退的操作,并且该方法等同于:window.location.href = url。示例代码如下:
<body>
<button>打开百度</button>
<button>打开百度</button>
</body>
<script>
let btnObjs = document.querySelectorAll('button');
btnObjs[0].addEventListener('click',function(){
window.location.assign('https://www.baidu.com'); //在当前页面打开
})
btnObjs[1].addEventListener('click',function(){
window.open('https://www.baidu.com') //跳转到一个新的网页
})
</script>
7.2.3新页面替换当前页面
语法:window.location.replace(网址)
用新的页面替换当前页面,不会产生历史记录,也就是说,不能进行前进后退操作。示例代码如下:
<body>
<button>打开百度</button>
<button>打开百度</button>
<button>打开百度</button>
</body>
<script>
let btnObjs = document.querySelectorAll('button');
btnObjs[0].addEventListener('click',function(){
window.location.assign('https://www.baidu.com'); //在当前页面打开
})
btnObjs[1].addEventListener('click',function(){
window.open('https://www.baidu.com') //跳转到一个新的网页
})
btnObjs[2].addEventListener('click',function(){
window.location.replace('https://www.baidu.com')//替换当前页面
})
</script>
7.3 history对象
history对象用来记录用户访问过的url的集合,即用户的历史记录,通过浏览器的前进和后退按钮实现前一页和后一页。
先初步了解几个用法:
方法 | 说明 |
history.back() | 回退到上一个页面 |
history.forward() | 跳转到下一个页面 |
history.go(number) | 跳转到指定页面,正数表示向前,负数表示向后 |
7.4 navigator对象
navigator对象记录当前浏览器的信息,用于识别不同的浏览器。
一般通过使用navigator对象身上的“userAgent”属性来判断浏览器的信息,该属性返回一个字符串,也就是浏览器的内层信息,不同的浏览器具有不同的userAgent,但要注意IE浏览器要使用特殊对象“ActiveXObject”。示例代码如下:
<body>
<h1>浏览器检测示例</h1>
<div id="browser-info" class="browser-info unknown">
<p>正在检测您使用的浏览器...</p>
</div>
<script>
// 获取元素引用
const infoElement = document.getElementById('browser-info');
const userAgent = window.navigator.userAgent.toLowerCase();
// 使用特性检测优先,浏览器检测作为后备
function detectBrowser() {
// 检测 IE(包括 IE11)
if (window.ActiveXObject !== undefined || document.documentMode === 11) {
return { name: 'IE', className: 'ie' };
}
// 检测 Firefox
if (userAgent.includes('firefox')) {
return { name: 'Firefox', className: 'firefox' };
}
// 检测 Edge Chromium(必须在 Chrome 检测前)
if (userAgent.includes('edg')) {
return { name: 'Edge Chromium', className: 'edge' };
}
// 检测 Chrome 或基于 Chromium 的浏览器
if (userAgent.includes('chrome')) {
return { name: 'Chrome 或 Chromium 内核', className: 'chrome' };
}
return { name: '未知浏览器', className: 'unknown' };
}
// 显示检测结果
const { name, className } = detectBrowser();
infoElement.className = `browser-info ${className}`;
infoElement.innerHTML = `<p>您正在使用: <strong>${name}</strong></p>`;
</script>
</body>
7.5定时器
我们平时使用的闹钟就是一种定时器,每隔一段时间执行一次,在JavaScript中,window对象提供了两个有用的定时器,分别是:
- setTimeout(),延时定时器
- setInterval(),间隔定时器
7.5.1启动延时定时器
语法:window.setTimeout(功能函数,延时的毫秒数)
点击页面的按钮,将页面上的div内容在3秒之后隐藏,示例代码如下:
<body>
<div>helloworld</div>
<button>3秒之后隐藏div</button>
</body>
<script>
let btnObj = document.querySelector('button');
btnObj.addEventListener('click',function(){
setTimeout(function(){
let divObj = document.querySelector('div');
divObj.style.display = 'none';
},3000);
})
</script>
7.5.2取消延时定时器
语法:window.clearTimeout(timerId)
根据指定的timerId取消指定的演示定时器。示例代码如下:
<body>
<button>取消延时定时器</button>
</body>
<script>
let timerId = setTimeout(function(){
console.log('定时器启动了。。。');
},3000);
let btnObj = document.querySelector('button');
btnObj.addEventListener('click',function(){
//取消定时器
clearTimeout(timerId);
console.log('定时器被取消了。')
})
</script>
7.5.3启动间隔定时器
语法:window.setInterval(功能函数,间隔的秒数)
作用是每隔指定的时间就重复调用对应的函数,示例代码如下:
<script>
setInterval(function(){
console.log('helloworld');
},1000);
</script>
7.5.4取消间隔定时器
语法:window.clearInterval(timerId)
根据指定的timerId取消间隔定时器,示例代码如下:
<script>
let cnt = 0;
let timerId = setInterval(function(){
console.log('helloworld');
cnt++;
if(cnt===3){
clearInterval(timerId);
console.log('执行完毕');
}
},3000)
</script>
7.6今典案例
7.6.1显示时钟
在页面上显示当前的系统时间。使用Date日期函数,同时还需要时间格式化,并且间隔定时器每隔1秒输出。示例代码如下:
<body>
<div></div>
</body>
<script>
function showTime(){
let datetime = new Date();
let year = datetime.getFullYear();
let month = datetime.getMonth() + 1;
let date = datetime.getDate();
let hours = datetime.getHours();
let minutes = datetime.getMinutes();
let seconds = datetime.getSeconds();
let res = year + '年' + month + '月' + date + '日' + hours + '时' + minutes + '分' + seconds + '秒';
document.querySelector('div').innerText = res;
}
showTime();
//注意这里传递一个函数引用,后面不要加括号,否则只会执行一次
setInterval(showTime,1000);
//setInterval(showTime(),1000); 这里的函数会立刻执行一次,然后将返回值传递给setInterval
</script>
7.6.2显示和隐藏切换
将页面上的div中的内容每隔2秒切换显示和隐藏。示例代码如下:
<body>
<div>helloworld</div>
</body>
<script>
let divObj = document.querySelector('div');
let flag = true;
window.setInterval(function(){
if(flag){
divObj.style.display='none';
flag = false;
}else{
divObj.style.display='block';
flag = true;
}
},2000)
</script>
7.6.3实现文本框内容校验
页面上有一个文本输入框,当文本框失去焦点时,页面提示“正在校验中...”,一秒后,若输入框的内容是“hello”,则页面提示“用户名不可用”,否则页面提示“用户名可用”。示例代码如下:
<body>
用户名:<input type="text"> <span></span>
</body>
<script>
document.querySelector('input').onblur = function(){
setTimeout(function(){
if(document.querySelector('input').value === 'hello'||){
document.querySelector('span').innerText = '用户名不可用';
}else{
document.querySelector('span').innerText = '用户名可用';
}
},1000);
document.querySelector('span').innerText = '正在校验中...';
}
</script>
7.6.4模拟验证码发送
点击页面上“发送验证码”按钮,按钮的文本显示倒计时,时间到了之后按钮恢复原样。示例代码如下:
<body>
<button>发送验证码</button>
</body>
<script>
let btnObj = document.querySelector('button');
let seconds = 10;
btnObj.addEventListener('click',function(){
this.disabled = true;
let timerId = setInterval(function(){
if(seconds>0){
btnObj.innerText = '倒计时' + seconds + '秒';
seconds--;
}else{
clearInterval(timerId);
btnObj.innerText = '发送验证码';
btnObj.disabled = false;
seconds = 10;
}
},1000)
})
</script>