JavaScript学习记录02

        笔者最近在学习郭超老师著的《JavaScript快速入门与开发实战》,文章内容主要是本人对书本内容学习的记录。内容不是将书本内容完全复现,只记载了笔者认为较为重要或是容易遗忘的内容。02已完结。

目录

6.DOM操作

6.1获取元素及内容

6.1.1根据id获取元素

6.1.2根据标签名获取元素

6.1.3根据name获取元素

6.1.4根据类名获取元素

6.1.5根据选择器获取元素

6.1.6获取和设置元素内容操作

6.2属性操作

6.2.1事件属性

6.2.2获取内置属性

6.2.3设置内置属性

6.2.4获取自定义属性

6.2.5设置自定义属性

6.2.6H5自定义属性的规范

6.2.7移除属性

6.2.8表单属性

6.3样式操作

6.3.1行内样式操作

6.3.2类名样式操作

6.4节点操作

6.4.1获取父节点

6.4.2获取子节点

6.4.3获取兄弟节点

6.4.4创建及添加节点

6.4.5删除节点

6.4.6复制节点

6.4.7创建及设置属性节点

6.5 DOM事件

6.5.1注册事件

6.5.2删除事件

6.5.3事件流

6.5.4事件对象

6.5.5阻止事件冒泡

6.5.6阻止事件默认行为

6.5.7事件委派

6.5.8窗口事件

6.5.9鼠标事件

6.5.10键盘事件

6.5.11表单事件

6.6经典案例

6.6.1简易版新闻评论

6.6.2稍微复杂版新闻评论

6.6.3全选案例

6.6.4隔行变色案例

7.BOM操作

7.1window对象

7.1.1警告框

7.1.2确认框

7.1.3提示框

7.1.4打开窗口

7.1.5关闭窗口

7.2 location对象

7.2.1重新加载页面

7.2.2跳转其他页面

7.2.3新页面替换当前页面

7.3 history对象

7.4 navigator对象

7.5定时器

7.5.1启动延时定时器

7.5.2取消延时定时器

7.5.3启动间隔定时器

7.5.4取消间隔定时器

7.6今典案例

7.6.1显示时钟

7.6.2显示和隐藏切换

7.6.3实现文本框内容校验

7.6.4模拟验证码发送


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表示,当然就有子节点和父节点,也有平级的节点,如兄弟节点,一个子节点只有一个父节点,但可以有多个子节点。

节点类型nodeTypenodeNamenodeValue
文档(documen)9#documentnull
元素(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标准事件流包括三个阶段,分别是:

  1. 事件捕获阶段,实际目标“div”在捕获阶段不会接收事件,事件从“document”到“html”再到“body”结束。
  2. 处于当前目标阶段,事件在实际目标“div”上被处理,实际上事件处理会被看作成冒泡阶段的一部分。
  3. 事件冒泡阶段,事件在实际目标发生后,逐层向上沿着节点传递,最终至“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”。

        事件对象有些注意事项:

  1. 事件发生时,浏览器才会创建事件对象,不需要开发者创建,并且事件对象只能在相应的程序内访问,事件执行完后,事件对象自动销毁;
  2. 事件对象的访问,对于大部分浏览器,只需要在函数的形参中定义 event 参数即可,对于早期的浏览器,需要通过“window.event”去获取;
  3. 考虑兼容性问题,要获取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次,明显前者效率更高;
  • 对于动态生成的元素节点,即便元素是事后添加的,使用动态绑定(如createElementappendChild等方法)事件和事件监听(如addEventListener)都不能为这样的元素注册事件,必须使用事件委派;
  • 还要注意的是,事件委派中应该使用“event.target”来获取触发事件的元素,不同于以往使用的“this”。

6.5.8窗口事件

        由窗口window节点对象触发的事件,常见的用法如下:

事件说明
onload整个文档加载完毕之后触发,包括图片,css文件等资源
DOMContentLoadedDOM加载完成就触发,不必等待图片、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>

        

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值