文章目录
一、web APIs
1.JS的组成
java script包含ECMAScript(语法)、DOM(页面文档对象模型)、BOM(浏览器对象模型)
后面两者属于web APIs阶段,主要学习页面交互功能。
2.API
- API是一些预先定义的函数,目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力,而又无须访问源码,或理解内部工作机制的细节。也就是给程序员提供一种工具,以便能够更轻松的实现想要完成的功能。
- MDN详细API:https://developer.mozilla.org/zh-CN/docs/Web/API
- Web API一般有输入和输出(函数的传参和返回值),WebAPI很多都是方法(函数)
3.DOM
二、DOM
1.DOM简介
即文档对象模型,是W3C组织推荐的处理可扩展标记语言(HTML或者XML)的标准变成接口。可通过接口改变网络的内容、结构和样式
2.DOM树
a.文档:一个页面就是一个文档,DOM中使用document表示
b.元素:页面中的所有标签都是元素,DOM中使用element表示
c.节点:网页中所有的内容都是节点(标签、属性、文本、注释等),DOM中使用node表示
3.获取元素
获取元素有以下几种方法:
1.根据ID获取
使用getElementById()
方法可以获取带有ID的元素的对象
<div id = "time">2022-10-01</div>
<script>
//1..因为我们的文档页面是从上往下加载,所以先得有标签,所以script写到标签的下面
//2..get获得element元素by通过 驼峰命名法
//3.. 参数id是大小写敏感的字符串
//4..返回的是一个元素对象
var timer = document.getElementById('tiem');
console.log(timer); //<div id = "time">2022-10-01</div>
console.log(typeof timer); //object
//5..console.dir打印我们返回的元素对象 更好的查看里面的属性和方法
console.dir(timer);
</script>
2.根据标签名获取
使用getElementsByTagName()方法可以返回带有指定标签名的对象的集合。
注意
返回的是 获取过来的元素对象的集合 以伪数组的形式存储
得到的元素对象是动态的,意思是原来li中的元素变了,得到的也会随之改变
<body>
<ul>
<li>我爱学习</li>
<li>我爱学习</li>
<li>我爱学习</li>
<li>我爱学习</li>
<li>我爱学习</li>
</ul>
<script>
// 1..返回的是 获取过来的元素对象的集合 以伪数组的形式存储
var lis = document.getElement.getElementsByTagName('li');
console.log(lis);
// 2..可以采取遍历的方式依次打印里面的元素
for(var i = 0;i < lis.length; i++){
console.log(lis[i]);
}
//3..如果页面中只有一个li 返回的还是伪数组的形式
//4..如果页面中没有这个元素,则返回一个空的伪数组
</script>
</body>
- 还可以获取某个元素(父元素)内部所有指定标签名的子元素.但注意这种方法中父元素必须是单个对象(必须指明是哪一个元素对象),获取的时候不包括父元素自己
<body>
<ol>
<li>我爱学习</li>
<li>我爱学习</li>
<li>我爱学习</li>
<li>我爱学习</li>
<li>我爱学习</li>
</ol>
<script>
var ol = document.getElementsByTagName('ol');
console.log(ol.getElementsByTagName('li')); //这样会报错,可以理解为ol或许很多,我们必须指明是哪一个ol
console.log(ol[0].getElementsByTagName('li')); // 这样就可以获取到五个li
var ol1 = document.getElementById('ol');
console.log(ol.getElementsByTagName('li'));
</script>
</body>
- 通过HTML5新增的方法获取
<body>
<div class="box">盒子</div>
<div class="box">盒子</div>
<div id="nav">
<ul>
<li>首页</li>
<li>产品</li>
</ul>
</div>
<script>
//1.getElementsByClassName() 根据类名获得某些元素
var boxs = document.getElemensByClassName('box');
console.log(boxs);
//2.querySelector()根据指定选择器返回第一个元素对象,返回的是指定选择器的第一个元素对象,切记里面的选择器需要加符号
var firstBox = document.querySelector('.box'); //.box说明是类选择器
console.log(firstBox);
var nav = document.querySelector('#nav');
console.log(nav);
var li = document.querySelector('li');
console.log(li);
//3. querySelectorAll()返回指定选择器的所有元素对象集合
var allBox = document.querySelectorAll('.box');
console.log(allBox);
var lis = document.querySelectorAll('li);
console.log(lis);
</script>
- 特殊元素获取
比如body、html
<body>
<script>
//1.. 获取body元素
var bodyEle = document.body;
console.log(bodyEle); //可以得到body标签
//2..获取html元素
var htmlEle = document.html;
console.log(htmlEle);// 返回undefined,html元素比较特殊,不能采用这种方法获得
var htmlEle1 = document.documentElement;
console.log(htmlEle); //可以得到
</script>
</body>
4.事件基础
javascript使我们有能力创建动态页面,而事件是可以被javascript侦测到的行为。
简单理解:触发-------响应机制
网页中的每个元素都可以产生某些可以触发javascript的事件,比如我们可以在用户点击某按钮时产生一个事件,然后去执行某些操作
<body>
<button id = "btn">唐伯虎</button>
<script>
//点击一个按钮,弹出对话框
// 1.事件是由三部分组成:事件源、事件类型、事件处理程序
// (1)事件源:事件被触发的对象 ,谁被触发了-----》按钮
var btn = document.getElementById('btn');
// (2)事件类型 如何促发 什么事件 比如鼠标点击(onclick) 还是鼠标经过 还是键盘按下
// (3)事件处理程序 通过一个函数赋值的方式 完成
btn.onclick = function(){
alert('点秋香');
}
</script>
</body>
执行事件的步骤:1.获取事件源 2.注册事件(绑定事件)3.添加事件处理程序(采取函数赋值的形式)
5.操作元素
- 改变元素内容的两种方法
//element.innerText 从起始位置到终止位置的内容,但它去除html标签,同时空格和换行也会去掉
//element.innerHTML 起始位置到终止位置的全部内容,包括html标签,同时保留空格和换行
<body>
<button>显示当前系统时间</button>
<div>某个时间</div>
<script>
// 当我们呢点击了按钮,div里面的文字会发生变化
// 1.获取元素
var btn = document.querySelector('button');
var div = document.querySelector('div');
// 2.注册事件
btn.onclick = function(){
div.innerText = '2022-10-01';
}
</script>
</body>
- innerText和innerHTML的区别
<body>
<div></div>
<p>
我是文字
<span>123</span>
</p>
<script>
// 1.innerText不识别html标签 非标准
var div = document.querySelector('div');
div.innerText = '<strong>今天是:</strong> 2019'; //无任何变化,且strong标签被当文本显示了
// 2.innerHtml 识别html标签,W3c标准
div.innerHtml = '<strong>今天是:</strong> 2019'; //识别了
//这两个属性时可读写的,可以获取元素里面的内容
var p = document.querySelector('p');
console.log(p.innerText); //会显示 我是文字123,但是他会去除空格和换行
console.log(p.innerHtml); //保留空格和换行
</script>
</body>
- 修改元素的属性
<body>
<button id = "ldh">刘德华</button>
<button id = "zxy">张学友</button>
<img src = "images/ldh.jpg" alt = "" title="刘德华">
<script>
//修改元素属性 src
//1. 获取元素
var ldh = document.getElementById('ldh');
var zxy = document.getElementById('zxy');
var img = document.querySelector('img');
//2.注册事件 处理程序
zxy.onclick = function(){
img.src = 'images/zxy.jpg';
img.title = '张学友';
}
ldh.onclik = function(){
img.src = "images/ldh.jpg";
img.title = '刘德华';
}
</script>
</body>
案例:分时显示不同的图片,显示不同的问候语
根据不同的时间,页面显示不同的图片,同时显示不同的问候语。
如果上午打开,显示上午好,显示上午的图片。以此类推
分析:根据系统不同时间来判断,所以需要用到日期内置对象
利用多分枝语句来设置不同的图片
需要一个图片,并且根据时间修改图片,就需要用到操作元素src属性
需要一个div元素,显示不同问候语,修改元素内容即可
<body>
<img src="images/s.gif" alt="">
<div>上午好</div>
<script>
//1.获取元素
var img = document.querySelector('img');
var div = document.querySelector('div');
//2.得到当前的小时数
var date = new Date();
var h = date.getHours();
//3.判断小时数改变图片和文字信息
if(h < 12){
img.src = 'images/s.gif';
div.innerHTML = '上午好';
}else if(h < 18){
img.src = 'images/x.gif';
div.innerHTML = '下午好';
}else{
img.src = 'images/w.gif';
div.innerHTML = '晚上好';
}
</script>
</body>
- 表单元素的属性操作
<body>
<button>按钮</button>
<input type="text" value="输入内容">
<script>
//1.获取元素
var btn = document.querySelector('button');
var input = document.querySelector('inpout');
//2.注册事件 处理程序
btn.onclick = function(){
//input.innerHTML = '点击了'; //不会显示,因为innerHTML是普通盒子比如div里面的内容,而表单里面的值(文字内容)是通过value来修改的
inpout.value = '被点击了';
//如果想要某个表单被禁用,不能再点击 disabled 我们想要这个按钮button禁用
btn.disabled = true;
this.disabled = true;//与上面效果相同,this指向事件函数的调用者btn
}
</script>
</body>
</body>
案例:仿京东显示密码
点击按钮将密码框切换为文本框,并可以查看密码明文
- 修改样式属性
<head>
<style>
div{
width:200px;
height:200px;
background-color:pink;
}
</style>
</head>
<body>
<div></div>
<script>
var div = document.querySelector('div');
div.onclick = function(){
this.style.backgroundColor = 'purple'; //div.style里面的属性 采取驼峰命名法
}
</script>
</body>
案例:关闭二维码
核心思路:利用样式的显示和隐藏完成,display:none隐藏元素,display:block显示元素
点击按钮,就让这个二维码盒子隐藏起来即可
案例:显示隐藏的文本
首先表单需要2个新事件,获得焦点onfocus,失去焦点onblur
如果获得焦点,先判断表单里面的内容是否为默认文字,如果是默认文字,就清空表单内容
如果失去焦点,先判断表单内容是否为空,如果是空,则表单内容改为默认文字
<head>
<style>
input{
color:#999;
</style>
</head>
<body>
<input type="text" value="手机">
<script>
//1.获取元素
var text = document.querySelector('input');
//2.注册事件,获得焦点事件onfocus
text.onfocus = function(){
if(this.value === '手机':{
this.value = '';
}
//获得焦点需要把文本框里面的文字颜色变黑
this.style.color = "#333';
}
text.onblur = function(){
if(this.value === '手机'{
this.value = '手机';
}
//失去焦点需要把文本框里面的文字颜色变浅
this.style.color = "#999';
}
</script>
</body>
6.排他思想
上面的操作都是只有一个元素的,如果有多个元素,该怎么办?
<body>
<button>按钮1</button>
<button>按钮2</button>
<button>按钮3</button>
<button>按钮4</button>
<button>按钮5</button>
<script>
//1.获取所有的按钮元素
var bts = document.getElementsByTagName('button');
//btns得到的是伪数组 里面的每一个元素btns[i]
for(var i = 0;i < btns.length; i++){
btns[i].onclick = function(){
//1.先把所有的按钮背景颜色都去掉
for(var i =0;i<btns.length;i++){
btns[i].style.backgroundColor = '';
}
//2.然后才让当前的元素背景颜色为pink
this.style.backgroundColor = 'pink';
}
</script>
</body>
百度换肤案例
就是点完图片,页面的背景图片会换成所点击的图片那样
分析:
- 这个案例联系的是给一组元素注册事件
- 给4个小图片利用循环注册点击事件
- 当我们点击了这个图片,让我们页面的背景改为当前的图片
- 核心算法:把当前的图片的src路径取过来,给body作为背景即可
<body>
<ul class = "baidu">
<li><img src = "images/1.jpg"></li>
<li><img src = "images/2.jpg"></li>
<li><img src = "images/3.jpg"></li>
<li><img src = "images/4.jpg"></li>
</ul>
<script>
//1.获取元素
var img = document.querySelector('.baidu').querySelectorAll('img');
//2.循环注册事件
for(var i = 0;i < imgs.legth;i++){
imgs[i].onclck = function(){
//this.src就是我们点击的图片的路径
document.body.style.backgroundImage = 'url('+this.src+')';
}
}
</script>
</body>
案例:表格隔行变色
分析:用到新的鼠标事件 鼠标经过onmouseover 鼠标离开onmouseout
核心思路:鼠标经过tr行,当前的行变背景颜色,鼠标离开去掉当前的背景颜色
<head>
<style>
.bg{
background-color:pink;
}
</style>
</head>
<body>
<table>
<thead>
<tr>
<th>代码</th>
<th>名称</th>
<th>最新公布净值</th>
<th>累计净值</th>
<th>前单位净值</th>
<th>净值增长率</th>
</tr>
</thead>
</thead>
<tbody>
<tr>
<td>003526</td>
<td>农行定期开放债券</td》
<td>1.075</td>
<td>1.079</td>
<td>1.074</td>
<td>+0.047%</td>
</tr>
<tr>
<td>003526</td>
<td>农行定期开放债券</td》
<td>1.075</td>
<td>1.079</td>
<td>1.074</td>
<td>+0.047%</td>
</tr>
</tbody>
</table>
<script>
//1.获取元素 tbody里面的所有的行
var trs = document.querySelector('tdoby').querySelectorAll('tr');
//2.利用循环绑定注册事件
for(var i = 0;i < trs.length; i++){
//3,鼠标经过事件onmouseover
trs[i].onmouseover = function(){
this.className='bg';//直接在css标签中写一个类会方便以后更改
}
trs[i].onmouseout = function(){
this.classNmae = '';
}
}
</script>
</body>
- 自定义属性的操作
a.获取属性值
<body>
<div id="demo"></div>
<script>
var div = document.querySelector('div');
//1.获取元素的属性值
//(1)element.属性,获取的是内置的属性值(元素本身自带的属性)
console.log(div.id);
//(2)element.getAttribute('属性'),获取的是自定义的属性(标准),我们程序员自定义的属性
log.console(div.getAttribute('id');//demo
</script>
</body>
b.设置属性值
element.属性=‘值’ 设置内置属性值
<body>
<div id="demo" index="1” class="nav"></div>
<script>
var div = document.querySelector('div');
//2.2设置元素属性值
//(1)element.属性='值'
div.id = 'test';
div.className = 'navs';
//(2)element.setAttribute('属性','值'); 主要正对自定义属性
div.setAttribute('index', 2);
div.setAttribute('class', 'footer');
</script>
</body>
c.移除属性
<body>
<div id="demo" index="1” class="nav"></div>
<script>
var div = document.querySelector('div');
//3.移除属性 removeAttribute(属性)
div.removeAttributw('index');
</script>
</body>
- H5自定义属性
自定义属性的目的:是为了保存并使用数据,有些数据可以保存到页面中而不用保存到数据库中
H5规定自定义属性data-开头作为属性名并且赋值
获取自定义属性,H5除了可以使用element.getAttribute('data-index‘);
H5h还新增了element.dataset.index或者element.dataset['index‘]
getAttribute兼容性要好一些
<body>
<div id="demo" index="1” class="nav" data-list-name="andy"></div>
<script>
var div = document.querySelector('div');
//H5新增的方法
console.log(div.dataset);//dataset是一个集合,里面存放了所有以data开头的自定义属性
console.log(div.dataset.index);
console.log(div.dataset['index']);
console.log(div.dataset.listName);//如果自定义属性里面有多个-链接的单词,我们获取的时候采取 驼峰命名法
console.log(div.dataset['listName']);
</script>
</body>
6.节点操作
-
节点操作的主要目的还是来获取元素
上面学的获取元素的方法:document.getElementById(),document.getElmentByName(),document.querySelector等
逻辑性不强,且繁琐。。所以现在来学利用节点层级关系获取元素 -
利用节点层级关系获取元素
利用父子兄节点关系获取元素
逻辑性强,但是兼容性稍差 -
节点概述
网页中的所有内容都是节点(标签、属性、文本、注释等),在DOM中节点使用node来表示
HTML DOM树中所有节点均可以通过javascript来进行访问,所有HTML元素(节点)都可以被修改,也可以创建或删除。一般情况下,节点至少拥有nodeType(节点类型)、nodeName(节点名称)和nodeValue(节点值)这三个基本属性
规定:元素节点noedeType为1,属性节点nodeType为2,文本节点nodeType为3(文本节点包含文字、空格、换行等)
<body>
<div>我是div</div>
<span>我是span</span>
<ul>
<li>我是li</li>
<li>我是li</li>
<li>我是li</li>
<li>我是li</li>
</ul>
<div class="box">
<span class="erweima">x</span>
</div>
<script>
var box = document.querySelector('.box');
</script>
</body>
- 节点层级
DOM树可以把节点划分成不同的层级关系,常见的是父子兄弟层级关系
父级节点
<body>
<div>我是div</div>
<span>我是span</span>
<ul>
<li>我是li</li>
<li>我是li</li>
<li>我是li</li>
<li>我是li</li>
</ul>
<div class="box">
<span class="erweima">x</span>
</div>
<script>
//原始方法
var box = document.querySelector('.box');
//父节点,得到的是离其最近的父级节点,如果没有就返回为空
var erweima = document.querySelector('.erweima');
console.log(erweima.parentNode);
</script>
</body>
- 子节点
parentNode.childNodes返回包含指定节点的子节点的集合,该集合为即时更新的集合(标准)
parentNode.children(非标准)
,是一个只读属性,返回所有的子元素节点,它只返回子元素节点,其余节点不返回。
<body>
<div>我是div</div>
<span>我是span</span>
<ul>
<li>我是li</li>
<li>我是li</li>
<li>我是li</li>
<li>我是li</li>
</ul>
<div class="box">
<span class="erweima">x</span>
</div>
<script>
//原始方法
var ul = document.querySelector('ul');
var lis = ul.querySelectorAll('li');
//1.子节点 childNodes 得到所有的子节点 包含 元素节点,文本节点等等
console.log(ul.childNodes);
//如果只想获得里面的元素节点,则需要专门处理,这样很麻烦,所以不提倡
for(var i = 0;i < ul.childNodes.length;i++){
if(ul.childNodes[i].nodeType == 1){
console.log(ul.childNodes[i]);
}
}
//2.childern获取所有的子元素节点
console.log(ul.children);
</script>
</body>
- 子节点的相关操作
parentNode.firstChild返回第一个子节点,找不到则返回Null,同样,也是包含所有的节点
<body>
<div>我是div</div>
<span>我是span</span>
<ul>
<li>我是li</li>
<li>我是li</li>
<li>我是li</li>
<li>我是li</li>
</ul>
<div class="box">
<span class="erweima">x</span>
</div>
<script>
var ol = document.querySelector('ol');
//1.firstchild获取的第一个子节点, 不管是文本节点还是元素节点
console.log(ol.firstChild);// #text
console.log(ol.lastChild);
//2.firstElementChild返回第一个子元素节点,找不到则返回null,但是这种方法有兼容问题
console.log(ol.firstElementChild);//<li>我是li</li>
console.log(ol.lastElementChild);//<li>我是li</li>
//3.实际开发的写法,既没有兼容性问题又返回第一个子元素
console.log(ol.children[0]);
</script>
</body>
- 案例:下拉菜单
<body>
<ul class="nav">
<li>
<a href="#">微博</a>
<ul>
<li>
<a href="">私信</a>
</li>
<li>
<a href="">评论</a>
</li>
<li>
<a href="">@wo</a>
</li>
</ul>
</li>
<li>
<a href="#">微博</a>
<ul>
</ul>
</li>
<li>
<a href="#">微博</a>
<ul>
</ul>
</li>
<li>
<a href="#">微博</a>
<ul>
</ul>
</li>
<script>
//1.获取元素
var nav = document.querySelector('.nav');
var lis = bav.children;//得到4个小li
//2.循环注册事件
for(var i = 0;i < lis.length;i++){
lis[i].onmouseover = function(){
this.children[1].style.display = 'block';
}
lis[i].onmouseout = function(){
this.children[1].style.display = 'none';
}
}
</script>
- 兄弟节点
node.nextSibling返回下一个兄弟节点,找不到则返回null ,同样也是包含所有的节点
node.previousSibling返回上一个兄弟节点,找不到返回Null,同样也是包含所有的节点
node.nextElementSibling返回下一个兄弟元素节点,找不到则返回null ,同样也是包含所有的节点
<body>
<div<我是div</div>//因为这里有一个换行
<span>我是span</span>
<script>
var div = document.querySelector('div');
//nextSibling 下一个兄弟节点 包含元素节点或者 文本节点等等
console.log(div.nextSibling); //#text
console.log(div.nextElementSibling); //<span>、、、
</script>
</body>
- 创建节点
document.createElement(‘tagName’) 方法创建由tagName指定的HTML元素,因为这些元素原先不存在,是根据我们的需求动态生成的,所以我们也成为动态创建元素节点。
<body>
<ul></ul>
<script>
//1.创建节点元素节点
var li = document.createElement('li');//还是没有,是因为这里只是创建了元素节点,还需要添加节点
</script>
</body>
- 添加节点
node.appendChild(child)方法将一个节点添加到指定父节点的子节点列表末尾,类似于css里面的after伪元素
node。insertBefore(child,指定元素)将一个节点添加到父节点的指定子节点的前面。类似于css里面的before伪元素
<body>
<ul></ul>
<script>
//1.创建节点元素节点
var li = document.createElement('li');//还是没有,是因为这里只是创建了元素节点,还需要添加节点
//2.添加节点node.appendChild(child) node为父节点,child为子级 后面追加元素 类似于数组中的push
var ul = document.querySelector('ul');
ul.appendChild(li); //打开发现ul里面有li了
//3.添加节点
var lili = document.createElement('li');
ul.insertBefore(lili,ul.children[0]);
</script>
</body>
- 删除节点
node.removeChild(child)从DOM中删除一个子节点,并返回删除的节点
<body>
<button>删除</button>
<ul>
<li>熊大</li>
<li>熊二</li>
<li>光头强</li>
</ul>
<script>
//1.获取元素
var ul = document.querySelector('ul');
//2.2删除
ul.removeChild(ul.children[0]);
//3.点击按钮依次删除里面的孩子
btn.onclick = function(){
if(ul.children.length == 0){
this.disabled = true;
}else{
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');
var lili = ul.children[0].cloneNode();//只复制了标签,不复制内容
li.appendChild(lili);
</script>
</body>
案例:动态生成表格
因为表格里面的数据都是动态的,我们需要js动态生成,这里我们模拟数据,自己定义好数据,数据采取对象的形式存储
所有数据都是放到tbody里面的行里面
因为行很多,我们需要循环创建多个行(对应多少人)
<body>
<table cellspacing="0">
<thead>
<tr>
<th>姓名</th>
<th>科目</th>
<th>成绩</th>
<th>操作</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<script>
//1.先去准备好学生的数据
var datas = [
{
name:'张三',
subject:'javascript',
score:100
},{
name:'李四',
subject:'javascript',
score:90
},{
name:'李四',
subject:'javascript',
score:90
}];
//2.往tbody里面创建行,有几个人就创建几行,数组的长度
var tbody = document.querySelector('tbody');
for(var i = 0;i < datas.length;i++){
var tr = document.createElement('tr');
tbody.appendChild(tr);
//行里面创建单元格td 单元格的数量取决于每个对象里面的属性个数
for(var k in datas[i]){
//创建单元格
var td = document.createElement('td');
//创建单元格的同时把对象里面的属性值 给td
td.innerHTML = datas[i][k];
tr.appendChild(td);
}
//3.创建有删除2个字的单元格
var td = document.createElement('td');
td.innerHTML = <a href="javascript:;">'删除'</a>;
tr.appendChild(td);
}
//4.删除操作
var as = document.querySelectorAll('a');
for(var i = 0;i < as.length;i++0){
as[i].onclick = function(){
//点击a删除当前a所在的行(链接的爸爸的baba)
tbody.remnoveChild(this.parentNode.parentNode)
}
</script>
</body>
注
for(var k in obj){
k得到的是属性名
obj[k] 得到的是属性
}
- 三种动态创建元素
a.document.write()如果页面文档流加载完毕,再调用这句话会导致页面重绘
document.write('<div>123</div>');
b.element.innerHtml 为拼接字符串的方式,比较耗时。但是创建多个元素效率更高(不要拼接字符串,采取数组形式拼接),结构稍微复杂
c.document.createElement() 创建多个元素效率稍微低一点点,但是结构更清晰
三、事件高级
1.元素注册事件的两种方式
- 注册事件(绑定事件)
给元素添加事件,成为注册事件或者绑定事件
注册事件有两种方式:传统方式和方法监听注册方式
(1)传统注册方式,
特点
:注册事件的唯一性,也就是同一个元素同一个事件只能设置一个处理函数,最后注册的处理函数将会覆盖前面注册的处理函数
比如利用on开头的事件onclick
(2)方法监听注册方式:W3C标准,为推荐方式
addEventListener()它是一个方法
特点
:同一个元素同一个事件可以注册多个监听器
eventTarget.addEventListener(type, listener[, useCapture])将指定的监听器注册到eventTarget(目标对象)上,当该对象触发指定的事件时,就会执行事件处理函数
type:事件类型字符串,比如click、mouseover,注意这里不要带on
listener:事件处理函数,事件发生时,会调回该监听函数
useCapture:可选参数,是一个布尔值,默认为false
<body>
<button>传统注册事件</button>
<button>方法监听注册事件</button>
<script>
var btns = document.querySelectorAll('button');
//1.传统方式注册事件
btns[0].onclickfunction(){
alert('hi');
}
btns[0].onclickfunction(){ //这样的结果就是只会弹出how are you
alert('how are you');
}
//2.事件监听注册事件,addEventListener里面的事件类型是字符串 必定加引号 而且不带on
btns[1].addEventListener('click',function(){
alert(22);
})
btns[1].addEventListener('click',function(){ //与传统的方式不一样,这样会弹出两次
alert(33);
})
</script>
2.删除事件的两种方式
(1)传统
eventTarget.onclick = null;
(2)方法监听注册方式
eventTarget.removeEventListener(type, listener[, useCapture]);
<body>
<div>1</div>
<div>2</div>
<div>3</div>
<script>
var divs = document.querySelectorAll('div');
divs[0].onclick = function(){
alert(11);
//1.传统方式删除事件
divs[0].onclick = null; //这样第二次点击就不会再弹出了
}
divs[1].addEventListener('click', fn); //里面的fn不需要调用加小括号
function fn(){
alert(22);
divs[1].removeEventListener('click',fn);
}
</script>
</body>
3.DOM事件流的三个阶段
(一)事件流描述的是从页面中接受事件的顺序。
事件发生时会在元素节点之间按照特定的顺序传播,这个传播过程就是DOM事件流.
事件流分为3个阶段:
(1)捕获阶段
(2)当前目标阶段
(3)冒泡阶段
事件冒泡:IE最早提出,事件开始时由最具体的元素接受,然后逐级向上传播到DOM最顶层节点的过程。
注意
:
JS代码中只能执行捕获或者冒泡其中的一个阶段
onclick和attachEvent只能得到冒泡阶段。
addEventListener(type, listener[,useCapture])第三个参数如果是true,表示在事件捕获阶段调用事件处理车光绪。如果是false(不写默认为false),表示在事件冒泡阶段调用事件处理程序。
实际开发中我们很少使用事件捕获,我们更加关注事件冒泡
有些事件是没有冒泡的,比如onblur、onfocus、onmoiusenter、onmouseleave
<div class = "father">
<div class = "son">son盒子</div>
</div>
<script>
//DOM事件流三个阶段
//1.js代码中只能执行捕获或者冒泡其中的一个阶段
//2.onclick和attachEvent(ie)只能得到冒泡阶段
//3.捕获阶段 如果addEventListener第三个参数是true那么则处于捕获阶段 捕获是document->html->body->father->son
var son = docuemnt.querySelector('.son');
son.addEventListener('click',function(){
alert('son');
},true); //点击后只有一个son弹出,注意这是没有下面father代码的情况
var father = docuemnt.querySelector('.father');
father.addEventListener('click',function(){
alert('father');
},true); //加上这个代码以后,会先弹出father,再弹出son,原因是现在处于捕获阶段,father会先被捕获
//4.冒泡阶段 如果addEventListener第三个参数是false 或者 省略,那么则处于冒泡阶段 son->father->body->html->document.所以下面的代码会先弹出son,再弹出father
var son = docuemnt.querySelector('.son');
son.addEventListener('click',function(){
alert('son');
});
var father = docuemnt.querySelector('.father');
father.addEventListener('click',function(){
alert('father');
});
</script>
4.事件对象
<body>
<div>123</div>
<script>
//事件对象
var div = document.querySelector('div');
div.onclick = function(event){
console.log(event); //会输出event的相关信息
}
div.addEventListener('click',function(event){
console.log(event); //同样会输出event的相关信息
})
//1.event就是一个事件对象,写到我们的侦听函数的小括号里面 当形参来看
//2事件对象只有有了事件才会存在,它是系统给我们自动创建的,不需要我们传递参数
//3.事件对象 是我们事件的一些列相关数据数据的集合 跟事件相关的 比如鼠标点击里面就包含了鼠标的相关信息,鼠标坐标啊,如果是键盘事件里面就包含了键盘事件的信息,吧hi如判断用户按下了哪个键
//4.这个事件对象我们可以自己命名 比如event、evt、e
//5.事件对象也有兼容性问题 ie678通过window.event
</script>
</body>
event对象代表事件的状态,比如键盘按键的状态、鼠标的位置,鼠标按钮的状态。
可以简单理解为:事件发生后,跟事件相关的一系列信息数据的集合都放在这个对象里面,这个对象就是事件对象event,它有很多属性和方法
事件对象常见的属性和方法
- e.target 返回
触发
事件的对象 标准 - e.srcElement 返回
触发
事件的对象 非标准ie6-8 - e.type 返回事件的类型 比如click mouseover 不带on
- e.cancelBubble 该属性阻止冒泡 非标准 ie6-8使用
- e.eturnValue 该属性阻止默认事件(默认行为) 非标准 ie6-8使用 比如不让链接跳转
- e.preventDefault 该方法阻止默认事件(默认行为) 标准 比如不让链接跳转
- e.stopPropagation 阻止冒泡 标准
5.封装阻止冒泡
事件冒泡:开始时由最具体的元素接受,然后逐级向上传播到DOM最顶层节点
事件冒泡本身的特性,会带来坏处,也会有好处
阻止冒泡:
标准写法:利用事件对象里面的stopPropagation()方法
<div class = "father">
<div class = "son">son盒子</div>
</div>
<script>
var son = docuemnt.querySelector('.son');
son.addEventListener('click',function(e){
alert('son');
e.stopPropagation(); //那么弹出son就不会再继续弹出father了
e.cancelBubble = true; //非标准 cancel 取消 bubble 泡泡
});
var father = docuemnt.querySelector('.father');
father.addEventListener('click',function(){
alert('father');
});
</script>
理解
:这里我只是再son上阻止了冒泡,点击son弹出son以后不会再弹出father。但是如果我点击father还是会弹出father
6.事件委托的原理
比如
<ul>
<li>1</li>
<li>1</li>
<li>1</li>
<li>1</li>
<li>1</li>
</ul>
这里我想要点击每个li都会弹出对话框,以前需要给每个li注册事件,是非常辛苦的,而且访问DOM的次数越多,这就会延长整个页面的交互就绪时间
那么就需要使用事件委托
,也称为事件代理,在jquery里面称为事件委派
事件委托的原理
不是每个子节点单独设置事件监听器,而是事件监听器设置在其父结点上,然后利用冒泡原理影响设置每个子节点。
那么,对于以上的案例:给ul注册点击事件,然后利用事件对象的target来找当前点击的li,因为点击li,事件会冒泡到ul上,ul有注册事件, 就会触发事件监听器。
<ul>
<li>1</li>
<li>1</li>
<li>1</li>
<li>1</li>
<li>1</li>
</ul>
<script>
var ul = document.querySelector('ul');
ul.addEventListener('click',function(e){
alter('1');
e.target.style.backgroundColor = 'pink'; //一点击背景颜色就会变成粉色
})
</script>
7.常用的鼠标事件
onclick 鼠标点击左键触发
onmouseover 鼠标经过触发
onmouseout 鼠标离开触发
onfocus 获得鼠标焦点触发
onblur 失去鼠标焦点触发
onmousemove 鼠标移动触发
onmouseup 鼠标谈起触发
onmousedown 鼠标按下触发
(1)禁止鼠标右键菜单
contextmenu主要控制应该何时显示上下文菜单,主要用于程序员取消默认的上下文菜单
selectstart 让文字无法选中
<body>
我是一段不愿意分享的文字
<script>
//1.禁用右键菜单
document.addEventListener('contextmenu', function(e){
e.preventDefault();
}) //那么选中这段文字将没有右键菜单,但是呢这种还是可以选中文字,ctrlC
//2.禁止选中文字 selectstart
document.addEventListener('selectstart',function(e){
e.preventDefault(); //这样的话这段文字都无法选中
})
</script>
</body>
(2)鼠标事件对象
event对象代表事件的状态,跟事件相关的一系列信息的集合。现阶段我们主要是用鼠标事件对象
MouseEvent和键盘事件对象KeyboardEvent
关于鼠标事件对象:
e.clientX 返回鼠标相对于浏览器窗口可视区的X坐标 、、不管鼠标怎么滚动,都只显示在当前可视区的位置
e.clientY 返回鼠标相对于浏览器窗口可视区Y坐标
e.pageX返回鼠标相对于文档页面的X坐标 IE9+支持 、、z这个就是整个文档页面,不管鼠标如何滚动
e.pageY返回鼠标相对于文档页面的Y坐标 IE9+支持
e.screenX 返回鼠标相对于电脑屏幕的X坐标
e.screenY 返回鼠标相对于电脑屏幕的Y坐标
(3)案例:跟随鼠标的天使
让天使图片一直跟着鼠标移动
分析:①鼠标不断地移动,使用鼠标移动事件:mousemove
②在页面中移动,给document注册事件
③图片要移动距离,而且不占位置,我们使用绝对定位即可
④核心原理:每次鼠标移动,我们都会获得最新的鼠标坐标,把这个x和y坐标作为图片的top和left值就可以移动图片。
<head>
<style>
img{
position:absolute;
top:2px;
</style>
<./head>
<body>
<img src="images/ange1.gif" alt="">
<script>
var pic = document.querySelector('img');
document.addEventListener('mousemove', function(e){
//1.mousemove只要我们鼠标移动1px,就会触发这个事件
var x = e,pageX;
var y = e.pageY;
//3.千万不要忘记给left和top添加px单位
pic.style.left = x + 'px';
pic.style.top= y + 'px';
});
</script>
</body>
8.常用的键盘事件
- 常用的键盘事件
onkeyup 某个键盘按键被松开时触发
onkeydown 某个键盘按键被按下时触发
onkeypress 某个键盘按键被按下时 触发但是
它不识别功能键 比如ctrl shift 箭头等
<script>
//常用的键盘事件
//1.keyup 按键弹起的时候触发
document.onkeyup = function(){
console.log('1'); //按下键盘松开的那一刻会输出1
})
//监听器的写法
document.addEventListener('keyup', function(){
console.log('1');
})
</script>
<script>
//常用的键盘事件
//2.键按下的时候就触发,只要不松开,就会一直触发
document.addEventListener('keydown', function(){
console.log('1');
})
</script>
<script>
//3.键按下就触发,只要不松开,就会一直触发
document.addEventListener('keypress', function(){
console.log('1');
})
</script>
三个事件的执行顺序: keydown --> keypress – >keyup
- 键盘事件对象
键盘事件对象中的KeyCode属性可以得到相应键的ASCII码值
<script>
document.addEventListener('keyup',function(e){
console.log(e.keyCode); //可以得到ASCII值
//keyup 和keydown事件不区分字母大小写
//keypress是区分大小写的
})
</script>
- 案例:只要用户输入了s键,光标自动到搜索栏并进行搜索
核心思路:检测用户是否按下了s键,如果按下了s键,就把光标定位到搜索框里面
分析:使用键盘事件对象里面的keyCode判断用户按下的是否是s键
搜索框获得焦点:使用js里面的focus()方法
<body>
<input type="text'>
<script>
var search = document.querySelector('input');
document.addEventListener('keydown',function(e){
if(e.keyCode ===83){
search.focus(); //搜索框获得焦点,但是使用keydown会使得s也会在搜索框中。所以应该使用keyup.相当于keydown一按就触发了search,然后抬起,所以输入了s。但是keyup抬起时才触发,所以搜索框不会有s
}
})
</script>
</body>
- 案例:模拟京东快递单号查询
要求:当我们在文本框中输入内容时,文本框上面自动显示大字号的内容
分析:快递单号输入内容时,上面的大号字体盒子(con)显示(这里面的字号更大)
表单检测用户输入:给表单添加键盘事件
同时把快递单号里面的值(value)获取过来赋值给con盒子(innerText)作为内容。
如果快递单号里面的内容为空,则隐藏大号字体(con)盒子
当失去焦点,就要隐藏这个con盒子
当获得焦点的时候,并且文本框内容不为空,就要显示这个con盒子
<body>
<div class="search”>
<div class="con">123</div>
<input type="text" placeholder="请输入您的快递单号" class="jd">
</div>
<script>
var con = document.querySelector('.con');
var jd_input = document.querySelector('.jd');
jd_input.addEventListener('keyup',function(){ //不使用keyup和keypress是因为一按下就立马触发,但是字还没有进去.使用keyup的话事件触发时,文字已经落入文本框了
if(this.style.value == ''){
con.style.display = 'none';
}else{
con.style.display = 'block';//上面的那个框框取消隐藏
con.innerText = this.value;
}
})
//当我们失去焦点就隐藏盒子
jd_input.addEventListener('blur', function(){
con.style.display = 'none';
})
//当我们获得焦点并且文本框内容不为空,就要显示这个con盒子
jd_input.addEventListener('focus',function(){
if(this.value !== ''){
con.style.display = 'block';
}
}
</script>
</body>