Web APIs 简介:
1、Web APIs 阶段与JS语法基础阶段的关联性?
2、什么是API ?
3、什么是 Web API ?
JS的组成:ECMAScript (JS语法)、 DOM、BOM(Web API)
目标:
-
什么是DOM,
-
DOM树
文档:一个页面就是一个文档,DOM中使用document表示。
元素:页面中的所有标签都是元素,DOM中使用element表示。
节点:网页中的所有内容都是节点(标签,属性,文本,注释等),DOM中使用node表示。
节点的属性
nodeName nodeType nodeValue 文档节点 #document 9 null 元素节点 标签名 1 null 属性节点 属性名 2 属性值 文本节点 #text 3 文本内容 DOM把以上内容看做是对象。
文档对象模型,是W3C组织推荐的处理可扩展的标记语言(HTML或者XML)的标准编程接口。
一、获取页面元素:
window.onload() 方法用于在网页加载完毕后立刻执行的操作,即当 HTML 文档加载完毕后,立刻执行某个方法。
window.onload() 通常用于 元素,在页面完全载入后(包括图片、css文件等等)执行脚本代码。
1、根据ID进行获取
document.getElementById(“time”)
//1,由于文档页面是从上往下面加载,所以script写在下面
//2,get 获得 element 元素 by 通过驼峰命名法
//3,参数 id 是大小写敏感的字符串
//4,返回的是一个元素对象
var timer = document.getElementById("time");
console.log(timer);
console.log(typeof timer);
//5,console.dir打印我们返回的元素对象,更好地查看里面的属性和方法
console.dir(timer);
getElementsByName() 通过name属性获取一组元素节点对象
2、根据标签名进行获取
getElementsByTagName()方法可以返回带有指定标签名的对象的集合。
还可以获取某个元素(父元素)内部所有指定标签名的子元素。
element.getElementByTagName(‘标签名’);
注意:父元素必须是单个对象(必须指明是哪一个元素的对象)。获取的时候不包括父元素自己。
<body>
<ul>
<li>把加班餐,不打扮的1</li>
<li>把加班餐,不打扮的2</li>
<li>把加班餐,不打扮的3</li>
</ul>
<ol id="ol">
<li>努努N年你1</li>
<li>努努N年你2</li>
<li>努努N年你3</li>
</ol>
<script>
//返回的是,获取过来元素对象的集合 以伪数组的形式存储的
var lis = document.getElementsByTagName("li");
console.log(lis);
console.log(lis[0]);
//2、想要依次打印里面的元素对象我们可以采用遍历的方式
for (var i = 0; i < lis.length; i++) {
console.log(lis[i]);
}
//3,如果页面中只有一个li ,返回的还是伪数组的形式。
//4、如果页面中没有这个元素返回的还是空的伪数组的形式
//5、element.getElementByTagName('标签名');父元素必须是指定的单个元素
var arrol = document.getElementsByTagName("ol"); // [ol] 获得是一个数组
console.log(arrol[0].getElementsByTagName("li"));
/* var ol = document.getElementById("ol"); //获得的是一个对象
console.log(ol.getElementsByTagName("li")); */
</script>
</body>
3、通过HTML5新增的方法获取
<body>
<div class="box">盒子1</div>
<div class="box">盒子2</div>
<div id="nav">
<ul>
<li>首页</li>
<li>产品</li>
</ul>
</div>
<script>
// 1、 document.getElementsByClassName('类名'); 根据类名返回元素对象的集合
var boxs = document.getElementsByClassName("box"); //以伪数组的形式存储
console.log(boxs);
var firstBox = document.querySelector(".box");
console.log(firstBox);
//2、 document.querySelector('选择器'); 根据指定选择器返回第一个元素的对象
// 注意:里面的选择器需要加符号 .box #nav
var nav = document.querySelector("#nav");
console.log(nav);
var li = document.querySelector("li");
console.log(li);
//3、document.querySelectorAll('选择器');根据指定选择器返回所有元素对象的集合
var allBox = document.querySelectorAll(".box");
console.log(allBox);
var lis = document.querySelectorAll("li");
console.log(lis);
</script>
</body>
4、特殊元素获取
-
能够给元素注册事件,
-
能够操作DOM元素的属性,
-
能够创建元素,
-
能够操作DOM的节点
获取body元素和获取html元素:
<body>
<script>
//1、获取 body元素
var bodyEle = document.body;
console.log(bodyEle);
// 2、 获取html元素
var htmlEle = document.documentElement;
console.log(htmlEle);
// 3、获取页面中的所有元素
var all = document.all;
// all = document.getElementsByTagName('*');同上
console.log(all);
</script>
</body>
二、事件基础
JS使我们有能力创建动态页面,而事件是可以被JS侦测到的行为。 简单理解:触发---->响应机制
1、事件有三部分组成:
(1)事件源(2) 事件类型 (3)事件处理程序
<body>
<button id="btn">唐伯虎</button>
<script>
//点击一个按钮弹出对话框
//(1)事件源 事件被触发的对象
var btn = document.getElementById("btn");
//(2)事件类型: 如何触发 什么事件? 例如:鼠标点击(onclick) 鼠标经过 还是键盘按下触发 或者 滚轮
//(3)事件处理程序 : 通过一个函数赋值的方式完成
btn.onclick = function () {
alert("点秋香");
};
</script>
执行事件的步骤:1,获取事件源 2,注册事件(绑定事件) 3,添加事件处理程序(采用函数赋值的方法)
//执行事件的步骤
//获取事件源
var div = document.querySelector("div");
//绑定事件 div.document
//添加事件处理程序
div.onclick = function () {
console.log("我被选中了");
};
鼠标事件 | 触发条件 |
---|---|
onclick | 鼠标点击左键触发 |
onmouseover | 鼠标经过触发 |
onmouseout | 鼠标离开触发 |
onfocus | 获得鼠标焦点触发 |
onblur | 失去鼠标焦点触发 |
onmousemove | 鼠标移动触发 |
onmouseup | 鼠标弹起触发 |
onmousedown | 鼠标按下触发 |
三、操作元素
JS的DOM操作可以改变网页的内容,结构和样式,可以利用DOM操作元素来改变元素里面的内容、属性等。注意以下都是属性
1、改变元素的内容
element.innerText
从起始位置到终止位置的内容,但他去除html的标签,同时空格和换行也会去掉
element.innerHTML
起始位置到终止位置的全部内容,包括HTML标签,同时保留空格和换行
<body>
<div></div>
<p>
我是蚊子
<span>1123</span>
</p>
<script>
// innerText 和 innerHTML 的区别
//1、innerText的使用方法 不识别html标签 非标准 去除空格和换行
var div = document.querySelector("div");
div.innerText = " <strong> 今天是:</strong> 2022";
//2、innerHTML的使用方法 识别html标签 W3C标准 保留空格和换行
// div.innerHTML = " <strong> 今天是:</strong> 2022";
// 这两个属性是可以读写的 可以获取元素里面的内容
var p = document.querySelector("p");
console.log(p.innerText);
console.log(p.innerHTML);
</script>
</body>
<style>
img {
width: 200px;
}
#panda {
margin-right: 80px;
}
</style>
</head>
<body>
<button id="panda">大熊猫</button>
<button id="yyy">小绵羊</button>
<br />
<img src="images/panda.webp" alt="" title="大熊猫" />
<script>
// 获取元素
var yyy = document.getElementById("yyy");
var panda = document.getElementById("panda");
var img = document.querySelector("img");
// 注册事件,处理程序
yyy.onclick = function () {
img.src = "images/yyy.webp";
img.title = "小绵羊";
};
panda.onclick = function () {
img.src = "images/panda.webp";
img.title = "大熊猫";
};
</script>
</body>
<!-- 根据不同时间,页面显示不同的图片,同时显示不同的问候语
如果上午时间打开页面,显示上午好,显示上午的图片
如果是下午时间打开页面,显示下午好,显示下午的图片
如果是晚上时间打开页面,显示晚上好,显示晚上的图片 -->
案列分析:
- 根据系统不同时间来判断,所以需要用日期的对象
- 利用多分支语句来设置不同的图片
- 需要一个图片,并且要根据时间修改图片,就需要用到操作元素src的属性
- 需要一个div元素,显示问候语,修改元素内容即可
<style>
img {
width: 300px;
}
</style>
</head>
<body>
<img src="images/skay.webp" alt="" />
<div>上午好</div>
<script>
//获取元素
var img = document.querySelector("img");
var div = document.querySelector("div");
//得到当前的小时数
var date = new Date();
var h = date.getHours();
//判断小时数来来改变图片和文字信息
if (h < 12) {
img.src = "images/skay.webp";
div.innerHTML = "亲,上午好";
} else if (h < 18) {
img.src = "images/dog.webp";
div.innerHTML = "亲,下午好";
} else {
img.src = "images/cat2.webp";
div.innerHTML = "亲,啊晚上好呀";
}
</script>
</body>
2、表单元素属性操作
利用DOM可以操作如下表单元素的属性:
type、value、checked、selected、disabled(禁用)
<body>
<button id="btn">按钮</button>
<input type="text" value="输入内容" name="" id="" />
<script>
var btn = document.getElementById("btn");
var input = document.querySelector("input");
btn.onclick = function () {
input.value = "大傻逼";
// btn.disabled = true;
this.disabled = true; //this 指向的是时间函数的调用者
};
</script>
</body>
仿京东显示密码:
<style>
* {
margin: 0;
padding: 0;
}
.box {
position: relative;
width: 400px;
border: 1px solid #ccc;
margin: 50px auto;
}
.box input {
width: 370px;
height: 30px;
outline: none;
border: 0;
}
.box img {
position: absolute;
width: 24px;
top: 4px;
right: 4px;
}
</style>
</head>
<body>
<!--1、核心思路:点击眼睛按钮,把密码框类型改为文本框就可以看见里面的密码 -->
<!--2、一个按钮可以分为两种状态,点击一次,切换为文本框,再点击一次,切换为密码框 -->
<!--3、利用一个flag变量,来判断flag的值,如果是1就切换为文本框,flag设置为0,
如果是0,就切换为密码框,flag设置为1-->
<div class="box">
<label for="">
<img src="images/close.png" alt="" id="eye" />
</label>
<input type="password" name="" id="pwd" />
</div>
<script>
//获取元素
var eye = document.getElementById("eye");
var pwd = document.getElementById("pwd");
//注册事件 处理程序
var flag = 0;
eye.onclick = function () {
if (flag == 0) {
pwd.type = "text";
eye.src = "images/open.png";
flag = 1;
} else {
pwd.type = "password";
eye.src = "images/close.png";
flag = 0;
}
};
</script>
</body>
3、样式属性操作
通过JS修改元素的大小,颜色,位置等样式 。
1,element.style 行内样式操作
2、element.className 类名样式操作
注意:
JS里面的样式采取驼峰命名法,比如 fontSize、backgroundColor
JS修改style样式操作,产生的是行内样式,CSS权重比较高。
如果样式较多,可以采取操作类名的方式更改元素的样式
class因为是个保留字,因此使用className来操作元素类名属性
className 会直接更改元素的类名,会覆盖原先的类名。(如果要保留原来的类名需要在原来的基础上再添加新的类名)。
<style>
div {
width: 600px;
margin: 100px auto;
}
.message {
display: inline-block;
font-size: 12px;
color: #999;
background: url(images/mess.png) no-repeat left center;
padding-left: 20px;
}
.wrong {
color: red;
background-image: url(images/wrong.png);
}
.right {
color: green;
background-image: url(images/right.png);
}
</style>
</head>
<body>
<div class="register">
<input type="password" class="ipt" />
<p class="message">请输入6~16位密码</p>
</div>
<script>
//1、首先判断的事件是表单失去焦点 onblur
//2、如果输入正确则提示正确的提示信息颜色为绿色小图标的变化
//3、如果输入的不是6-16 位,则提示错误信息颜色为红色 小图标的变化
// 4、因为里面变化样式较多,我们采取className修改样式
// 获取元素
var ipt = document.querySelector('.ipt');
var message = document.querySelector('.message');
//注册事件
ipt.onblur = function () {
if (ipt.value.length < 6 || ipt.value.length > 16) {
// console.log('错误');
message.className = 'message wrong';
message.innerHTML = '输入的位数错误';
} else {
message.className = 'message right';
message.innerHTML = '输入格式正确';
}
};
</script>
</body>
4、操作元素
操作元素总结:
操作元素:1、操作元素内容(innerText,innerHTML)2、操作常见的元素属性(src,href,title,alt)3、操作表单元素属性(type,value,disabled)4、操作元素样式属性(element.style , className)
自定义属性操作:
获取属性值:
element.属性 获取内置的属性(元素本身自带的属性)
element.getAttribute(‘属性’); 主要获得自定义的属性(标准) 程序员自定义的属性
设置属性值:
(1)element.属性 = ‘值’ 设置内置属性
(2) element.setAttribute(‘属性’,‘值’);主要针对自定义属性
(3)移出属性 removeAttribute(‘属性’);
<div id="demo" index="12" class="nav"></div>
<script>
var div = document.querySelector('div');
div.className = 'navs';
div.setAttribute('index', '90');
div.setAttribute('class', 'navs'); *//class 特殊 这里写的是class 不是className*
<script/>
H5自定义属性:
自定义属性的目的:是为了保存并使用数据。有些数据可以保存到页面中而不用保存到数据库中。
自定义属性获取是通过getAttribute(‘属性’) 获取。
但是有些自定义属性很容易引起歧义,不容易判断是元素的内置属性还是自定义属性。
H5给我们新增了自定义属性:
设置H5自定义属性:
H5规定自定义属性data-开头做为属性名并且赋值。
比如<div data-index= '1'></div>
或者使用JS设置element.setAttribute(‘data-index’,2);
获取H5自定义属性:
1,兼容性获取 element.getAttribute(‘data-index’);
2、H5新增element.dataset.index 或者 element.dataset[‘index’] ie 11才开始支持。
// H5新增的获取自定义属性的方法 它只能获取data-开头的
// dataset 是一个集合里面存放了所有以data开头的自定义属性
四、节点操作
获取元素通常使用两种方式:
1、利用DOM提供的方法获取元素
-
document.getElementByid()
-
document.getElementByTagName()
-
document.querySelector 等
逻辑性不强,比较繁琐
2、利用节点层级关系获取元素
- 利用父子兄弟节点关系获取元素
- 逻辑性强,但是兼容性稍微差
这两种方式都可以获取元素节点,我们后面都会使用,但是节点操作更简单
节点概述 :
网页中的所有内容都是节点(标签、属性、文本、注释等),在DOM中,节点使用node来表示。
HTML DOM树中的所有节点均可以通过JS进行访问,所有HTML元素(节点)均可以被修改,也可以创建或删除
**一般的,**节点至少拥有nodeType(节点类型)、nodeName(节点名称)和nodeValue(节点值)这三个基本属性
元素节点 nodeType 为 1
属性节点 nodeType 为 2
文本节点 nodeType 为 3(文本节点包含文字、空格、换行等)
实际开发中,节点操作主要操作的是元素节点。
节点层级:
利用DOM树可以把节点划分为不同的层级关系,常见的是父子兄弟层级关系
1、父级节点:
node.parentNode
- parentNode 属性可返回某节点的父节点,注意是最近的一个父节点
- 如果指定的节点没有父节点则返回null
2、子节点:
parentNode.childNodes(标准)子节点
parentNode.childNodes返回包含指定节点的子节点的集合,该集合为即时更新的集合。
注意:返回值里面包含了所有的子节点,包括元素节点,文本节点等。 在IE8及以下的浏览器中,不会将空白文本当成子节点。
如果只想获得里面的元素节点,则需要专门的处理,所以我们一般不提倡使用childNodes
//1,parentNode.childNodes(标准)子节点
// childNodes 所有有的子节点 包含 元素节点 文本节点等等
console.log(ul.childNodes);
var ul = document.querySelector('ul');
for (var i = 0; i < ul.childNodes.length; i++) {
if (ul.childNodes[i].nodeType == 1) {
console.log(ul.childNodes[i]);
}
}
parentNode.children(非标准)(重点使用)
是一个只读的属性,返回所有的子元素节点。它只返回了元素节点,其余节点不返回(重点掌握)
虽然children是一个非标准, 但是得到了各个浏览器的支持,因此我们可以放心使用。
parentNode.firstChild :返回的是第一个子节点,找不到则返回null * ( 同样,也是包含所有的节点)*
parentNode.firstElementChild 返回最后一个子元素节点,找不到则返回null
**注意:**这两个方法有兼容性问题,IE9 以上才支持。
// 3.实际开发中的写法 既没有兼容性问题又返回第一个子元素
console.log(ol.children[ol.children.length - 1]); //得到最后一个元素
3、兄弟节点:
1、node.nextSibling 返回的是当前元素的下一个兄弟节点,找不到返回null。同样,也包含所有的节点
2、node.previousSibling 返回当前元素的上一个兄弟节点,找不到 返回null。 同样,也包含所有的节点
3、node.nextELementSibling 返回的是当前元素的下一个兄弟节点,找不到返回null(IE9 以上)
//处理兼容性问题: 封装一个兼容性的函数
function getNextElementSibling(element) {
var el = element;
while ((el = el.nextSibling)) {
if (el.nodeType === 1) {
return el;
}
}
return null;
}
4、创建节点
(核心:先创建再添加)
document,createElement(‘tagName’)
此方法创建是由tagName指定的HTML元素。因为这些元素原先不存在,是根据我们的需求动态生成的,所以也称动态创建元素节点。
添加节点:
1、node.appendChild(child);
此方法将一个节点添加到指定父节点的子节点列表末尾。类似于CSS里面的after伪元素。
2、node.insertBefore(child,指定元素)
此方法将一个节点添加到父节点的指定节点前面。类似于CSS里面的before伪元素。
<body>
<ul>
<li>666</li>
</ul>
<script>
// 1,创建节点: 元素节点
var li = document.createElement('li');
// 2、 添加节点 node.appendCholed(child) node 父级 child 子级 后面追加元素
var ul = document.querySelector('ul');
ul.appendChild(li);
// 3、添加节点 node.insertBefore(child,指定元素)
var lili = document.createElement('li');
ul.insertBefore(lili, ul.children[0]);
// 4、添加一个元素: 先创建再添加
</script>
</body>
5、删除节点
node.removeChild(child);
此方法从DOM中删除一个子节点,返回删除的节点。
6、复制节点
node.cloneNode();
此方法返回调用该方法的节点的一个副本,也称为克隆节点。
注意:如果括号参数为空或者为false,则是浅拷贝,即只有克隆复制节点本身,不克隆里面的子节点。
如果括号里面为true,则为深拷贝。复制里面的内容。
节点操作:
三种动态节点创建元素的区别:
document.write()
是直接将内容写入到页面的内容流,但是文档流执行完毕之后,它会导致页面全部重绘
// 整个页面加载完之后才会执行JS
window.onload = function () {
document.write('<div>123</div>');
};
// 1、document.write() 创建元素 如果页面文档流加载完毕,再调用这句话会导致页面重绘
/* var btn = document.querySelector('button');
btn.onclick = function () {
document.write('<div>123</div>');
}; */
element.innerHTML:
innerHTML 是将内容写入某个DOM的节点,不会导致页面全部重绘
innerHTML 创建多个元素效率更高(不要拼接字符串,采取数组形式拼接 ,需要把数组转换为字符串),结构稍微复杂
document.createElement():
createElement() 创建多个元素效率稍微低一点点,但是结构更加清晰。
7、替换节点
replaceChild(); 可以使用指定的子节点替换已有的子节点
语法:父节点.replaceChild(新节点,旧节点);
8、DOM的重点核心:
主要针对于元素的操作:
-
创建 (document.write(),element.innerHTML,document.createElement())
-
增 (appendChild,insertBefore)、
-
删 (removeChild)、
-
改 (1、修改属性:src、href、title等,2、 修改普通元素内容:innerHTML、innerText 3、修改表单元素:value、type,disabled等 4、修改元素样式:style,className)
-
查 (主要获取查询DOM元素:1、DOM提供的API方法:getElementById,getElementByTagName,古老方法不太推荐。
2、H5提供的新增的方法:ququerySelector,ququerySelectorAll 提倡使用 3、利用节点操作来获取元素:父(parentNode),子(children),兄(previousElementSibling ,nextElementSibling)提倡使用)
-
属性操作 (主要针对自定义属性: 1、setAttribute:设置dom的属性值 2、getAttribute:得到dom的属性值 3、removeAttribute:移出属性)
-
事件操作
给元素注册事件,采取 事件源.事件类型 = 事件处理程序
鼠标事件 | 触发条件 |
---|---|
onclick | 鼠标点击左键触发 |
onmouseover | 鼠标经过触发 |
onmouseout | 鼠标离开触发 |
onfocus | 获得鼠标焦点触发 |
onblur | 失去鼠标焦点触发 |
onmousemove | 鼠标移动触发 |
onmouseup | 鼠标弹起触发 |
onmousedown | 鼠标按下触发 |
五、事件高级
- 能够写出元素注册事件的两种方式
- 能够说出删除事件的两种方式
- 能够说出DOM事件流的三个阶段
- 能够利用事件对象完成跟随鼠标案例
- 能够封装组织冒泡的兼容性函数
- 能够说出事件委托的原理
- 能够说出常用的鼠标和键盘事件
学习流程:
1、注册事件(绑定事件)2、删除事件(解绑事件)3、DOM事件流 4、事件对象 5、阻止事件冒泡 6、事件委托(代理 、委派)7、 常用的鼠标事件 8、常用的键盘事件
1、注册事件
注册事件有两种方式:传统方式和方法监听注册方式
传统注册方式:
- 利用on开头的事件 onclick
<button onclick= "alert('hi~')"></button>
- btn.onclick = function(){}
- 特点:注册事件的唯一性
- 同一个元素同一个事件只能设置一个处理函数,最后注册的处理函数将会覆盖前面注册的处理函数
方法监听注册方式:
- W3C标准 推荐方式
- addEventListener() 是一个方法
- IE9 之前不支持,可使用 attachEvent() 代替(该特性非标准的,请尽量不要在生产环境中使用它!)
- 特点:同一个元素同一个事件可以注册多个监听器
- 按注册顺序依次执行
eventTarget.addEventListener('type',listener[,useCapture])
eventTarget.addEventListener()
方法将指定的监听器注册到eventTarget(目标对象)上,当该对象触发指定的事件时,就会执行事件处理函数。
该方法接收三个参数:
type
:事件类型字符串(必须添加引号),比如click、mouseover,注意这里不带on
listener
:事件处理函数,事件发生时,会调用该监听函数
‘useCapture’:可选参数,是一个布尔值,默认是false。学完DOM事件流后,再进行下一步学习。
attachEvent 事件监听方式:
eventTarget.attachEvent(eventNameWithOn,callback)
eventTarget.attachEvent() 方法是将指定的监听器注册到eventTarget(目标对象)上,当该对象触发指定的事件时,指定的回调函数就会被执行。
该方法接收两个参数:
eventNameWithOn :事件类型字符串,比如onclick、onmouseover,这里要带on
callback : 事件处理函数,当目标触发事件时回调函数被调用。
// 3,attachEvent() ie9 以前的版本才支持
attachEvent('onclick', function () {
alert('123');
});
注册事件兼容性解决方案:
function addEventListener(element, eventName, fn) {
// 判断当前浏览器是否支持 addEventListener 方法
if (element.addEventListener) {
element.addEventListener(element, fn); //第三个参数 默认的是false
} else if (element.attachEvent) {
element.attachEvent('on' + eventName, fn);
} else {
// 相当于 element.onclick = fn;
element['on' + eventName] = fn;
}
}
兼容性处理原则;首先照顾大多数浏览器,再处理特殊浏览器。
2、删除事件
删除事件的方式:
(1)传统注册方式
eventTarget.onclick = null;
(2)方法监听注册方式
eventTarget.removeEventListener(type, listener[, useCapture]);
eventTarget.detachEvent (eventNameWithOn, callback);
<body>
<div>1</div>
<div>2</div>
<div>3</div>
<script>
// 点击一次之后再点击就不会提示
var div = document.querySelectorAll('div');
for (var i = 0; i < div.length; i++) {
// 1、传统的方式解绑
/* div[i].onclick = function () {
alert('haha');
this.onclick = null; //解绑事件
}; */
// 2、添加监听器的方式解绑
/* div[i].addEventListener('click', fn);
function fn() {
alert('haha');
this.removeEventListener('click', fn);
} */
// 3、
div[i].attachEvent('onclick', fn1);
function fn1() {
alert('666');
this.detachEvent('onclick', fn1);
}
}
</script>
</body>
3、DOM事件流
事件发生时会在元素节点之间按照特定的顺序传播,这个传播过程即DOM事件流。
DOM事件流分为三个阶段,分别为:
捕获阶段:事件从Document节点自上而下向目标节点传播的阶段;
目标阶段:真正的目标节点正在处理事件的阶段;
冒泡阶段:事件从目标节点自上而下向Document节点传播的阶段。
注意:
1、JS代码只能执行捕获或者冒泡其中一个阶段(要么是捕获要么是冒泡)
2、onclick和attachEvent(ie)只能得到冒泡阶段
3、addEventListener(type, listener[, useCapture]) 第三个参数如果是true,表示在事件捕获阶段调用事件处理程序;如果是false(不写默认是false),表示在事件冒泡阶段调用事件处理程序
4、实际开发中,我们很少使用事件捕获,我们更关注事件冒泡
5、有些事件是没有冒泡的,比如onblur、onfocus、onmouseenter、onmouseleave
6、事件的冒泡有时会带来麻烦,不过是可以被阻止的,方法是:stopPropagation()
stopPropagation() 方法:终止事件在传播过程的捕获、目标处理或冒泡阶段进一步传播。调用该方法后,该节点上处理该事件的处理程序将被调用,事件不再被分派到其他节点。
4、事件对象
官方解释:event对象代表事件的状态,比如键盘按键的状态,鼠标的位置,鼠标按钮的状态。
简单理解:事件发生后,跟事件相关的一系列信息数据的集合都放到这个对象里面,这个对象就是事件对象event,它有很多属性和方法:
比如:
1.谁绑定了这个事件
2.鼠标触发事件的话,会得到鼠标的相关信息,如鼠标位置。
2.键盘触发事件的话,会得到键盘的相关信息,如按了哪个键。
<style>
div {
width: 100px;
height: 100px;
background-color: pink;
}
</style>
</head>
<body>
<div>123</div>
<script>
var div = document.querySelector('div');
// 传统方式:
/* div.onclick = function (event) {
console.log(event);
}; */
// 处理IE678,兼容性写法
div.onclick = function (e) {
console.log(e);
e = e || window.event;
};
// 使用监听器
div.addEventListener('click', function (event) {
console.log(event);
});
/*
1、event 就是一个事件对象,写在侦听函数的 小括号里面 当形参来看
2、事件对象只有有了事件才会存在,它是系统为我们自动创建的,不需要我们来传递参数
3、事件对象 是 我们事件的一系列相关数据的集合,跟事件相关的
比如,鼠标点击里面就包含了鼠标的相关信息 ,鼠标坐标,如果是键盘事件里面就包含了键盘事件的信息
4、事件对象 可以自己命名 比如:event,evt,e
5、事件对象也有兼容性问题 IE678 通过 window.event 兼容性的写法 e = e || window.event; */
</script>
</body>
事件对象的常见属性和方法:
事件对象属性方法 | 说明 |
---|---|
e.target | 返回触发事件的对象 标准 |
e.srcElement | 返回触发事件的对象 非标准 IE678使用 |
e.type | 返回事件类型 比如click mouseover 不带on |
e.canceIBubble | 该属性阻止冒泡 非标准 IE678使用 |
e.returnValue | 该属性 阻止默认事件(默认行为)非标准 IE678使用 比如不让链接跳转 |
e.preventDefault() | 该方法 阻止默认事件(默认行为)标准 比如不让链接跳转 |
e.stopPropagation | 阻止冒泡 标准 |
<body>
<div>123</div>
<ul>
<li>abc</li>
<li>abc</li>
<li>abc</li>
</ul>
<script>
//常见的事件属性和方法
// 1、e.target返回的是触发事件的对象(元素) this返回的是绑定事件的对象(元素)
// 区别:e.target 点击了哪个元素,就返回哪个元素。this 谁绑定了这个点击事件,就返回谁。
var div = document.querySelector('div');
div.addEventListener('click', function (e) {
console.log(e.target);
console.log(this);
});
var ul = document.querySelector('ul');
ul.addEventListener('click', function (e) {
// 给ul绑定了是事件,那么 this 就指向ul
console.log(this);
console.log(e.currentTarget);
// e.traget 指向的点击的那个对象 谁触发了这个事件 当前点击的是 li e.traget 指向的就是li
console.log(e.target);
});
// 处理IE678 兼容性 了解
/* div.onclick = function (e) {
e = e || window.event;
var traget = e.traget || e.srcElement;
console.log(traget);
}; */
// 了解,跟this 有个非常相似的属性 currentTarget ie678不认识
</script>
</body>
<body>
<div>123</div>
<a href="http://www.baidu.com">百度</a>
<form action="http://www.baidu.com">
<input type="submit" value="提交" name="sub" />
</form>
<script>
// 返回事件类型
var div = document.querySelector('div');
div.addEventListener('click', fn);
div.addEventListener('mouseover', fn);
div.addEventListener('mouseout', fn);
function fn(e) {
console.log(e.type);
}
// 2、阻止默认事件
var a = document.querySelector('a');
a.addEventListener('click', fn1);
function fn1(e) {
e.preventDefault(e); //dom推荐的写法
}
// 3、传统的注册方式
a.onclick = function (e) {
// 普通浏览器 e.preventDefault();
// e.preventDefault(e);
// 低版本浏览器 IE678
// e.returnValue;
// 可以利用return false 也能阻止默认行为 没有兼容性问题
return false; //return 后面的代码不执行了而且只限于传统的注册方式
};
</script>
</body>
5、阻止事件冒泡
组织事件冒泡的两种方式:
事件冒泡:开始时由最具体的元素接收,然后逐级向上传播到DOM最顶层节点。
实现代码:
$("#three").click(function(event) {
event.stopPropagation();
});
a.写入event.stopPropagation(); 停止传播
事件处理过程中,阻止了事件冒泡,但不会阻止默认行为
e.cancelBubble = true; //取消冒泡 支持IE678
阻止事件冒泡的兼容性解决方案:
if (e && e.stopPropagation){
e.stopPropagation();
}else {
window.event.cancelBubble = true;
}
b.写入return false;
事件处理过程中,阻止了事件冒泡,也阻止了默认行为
c.写入event.preventDefault();
事件处理过程中,不阻止事件冒泡,但阻止默认行为
6、事件委托(代理 、委派)
事件冒泡本身的特性,会带来坏处,也会带来害处,需要我们灵活掌握。
事件委托的原理:
不是每个子节点单独设置事件监听器,而是事件监听器设置在其父节点上,然后利用冒泡原理影响设置每个子节点。
事件委托的作用:
我们只操作了一次DOM,提高了程序的性能。
<body>
<ul>
<li>地狱魔爵人</li>
<li>地狱魔爵人</li>
<li>地狱魔爵人</li>
</ul>
<!-- 点击每个li都会弹出对话框,以前,需要给每一个li注册事件,
而且访问DOM的次数越多,就会延长整个页面的交互就绪时间
给ul注册点击事件,然后利用事件对象的target来找到当前点击的li,
因为点击li,事件会冒泡到ul上, ul有注册事件就会触发事件监听器-->
<script>
var ul = document.querySelector('ul');
ul.addEventListener('click', function (e) {
alert(e.target.innerHTML);
// e.target 可以得到点击的对象
console.log(e.target);
e.target.style.background = 'pink';
});
</script>
</body>
7、 常用的鼠标事件
1、禁止鼠标右键菜单
contextmenu 主要控制应该何时显示上下文菜单,主要用于程序员取消默认的上下文菜单。
禁止鼠标选中
(selectstart 开始选中)
<body>
一行不愿意分享的文字;
<script>
// 禁止鼠标右键
document.addEventListener('contextmenu', function (e) {
e.preventDefault();
});
// 禁止选中文字 selectstart
document.addEventListener('selectstart', function (e) {
e.preventDefault();
});
</script>
</body>
2、鼠标事件对象
event对象代表事件的状态,跟事件相关的一系列信息集合。现阶段我们主要使用鼠标事件对象 MouseEvent 和键盘事件对象 KeyboardEvent
鼠标事件对象 | 说明 |
---|---|
e.clientX | 返回鼠标相对于浏览器窗口可视区的X坐标 |
e.clientY | 返回鼠标相对于浏览器窗口可视区的Y坐标 |
e.pageX | 返回鼠标相对于文档页面的X坐标 IE9+ 支持 |
e.pageY | 返回鼠标相对于文档页面的Y坐标 IE9+ 支持 |
e.screenX | 返回鼠标相对于电脑屏幕的X坐标 |
e.screenY | 返回鼠标相对于电脑屏幕的Y坐标 |
<style>
img {
position: absolute;
}
</style>
</head>
<body>
<img src="images/angel.gif" alt="" />
<script>
/* 1、鼠标不断移动,使用鼠标移动事件
2、在页面中移动,给document注册事件
3、图片要移动距离,而且不占用位置,要使用绝对定位
4、核心原理:每次鼠标移动,我们会获得最新的鼠标坐标,把这个X和Y坐标做为图片的top和left值就可以移动图片 */
var pic = document.querySelector('img');
document.addEventListener('mousemove', function (e) {
var x = e.clientX;
var y = e.clientY;
// 千万不要给left top 添加 px 单位
pic.style.left = x - 30 + 'px';
pic.style.top = y - 40 + 'px';
});
</script>
</body>
8、常用的键盘事件
键盘事件 | 触发条件 |
---|---|
onkeyup | 某个键盘按键被松开时触发 |
onkeydown | 某个键盘按键被按下时触发 |
onkeypress | 某个键盘按键 被按下时触发 但是它不识别功能按键 比如 ctrl shift 箭头等 |
<script>
// 1、keyup 按键弹起时触发
document.addEventListener('keyup', function () {
console.log('弹起up');
});
// 3、onkeypress某个键盘按键 被按下时触发 但是它不识别功能按键 比如 ctrl shift 箭头等
document.addEventListener('keypress', function () {
console.log('按下press');
});
// 2、onkeydown某个键盘按键被按下时触发 能够识别功能键
document.addEventListener('keydown', function () {
console.log('按下down');
});
// 4、三个事件的执行顺序 keydown keypress keyup
</script>
键盘事件对象:
<script>
// 键盘事件对象中的keyCode属性可以得到相应键的ASCII码值
document.addEventListener('keyup', function (e) {
console.log('up' + e.keyCode);
// 判断用户按下了哪个键
if (e.keyCode === 65) {
alert('您按下的a键');
}
});
// 1、keyup 和 keydown 事件不区分字母的大小写 a和A得到的都是65
// 2、keypress 事件区分大小写 a 97 A 65
document.addEventListener('keypress', function (e) {
console.log('press' + e.keyCode);
});
</script>
大小规则
常见ASCII码的大小规则:数字< 大写字母 < 小写字母。
1.数字比字母要小。如 “7”<“F”;
2.数字0比数字9要小,并按0到9顺序递增。如 “3”<“8” ;
3.字母A比字母Z要小,并按A到Z顺序递增。如“A”<“Z” ;
4.同个字母的大写字母比小写字母要小32。如“A”<“a” 。
几个常见字母的ASCII码大小: “A”为65;“a”为97;“0”为 48 [4] 。
六、BOM浏览器对象模型
能够说出什么是DOM
能够知道浏览器的顶级对象
能够写出页面加载事件以及注意事项
能够写出两种定时器函数并说出区别
能够说出JS执行机制
能够使用location对象完成页面之间的跳转
能够知晓navigator对象涉及的属性
能够使用history提供的方法实现页面的刷新
1、BOM概述:
BOM(Browser Object Model)即浏览器对象模型,它提供了独立于内容而与浏览器窗口进行交互的对象,其核心对象是window。
BOM由一系列相关的对象构成,并且每个对象都提供了很多方法与属性。
BOM缺乏标准,JavaScript语法的标准化组织是ECMA,DOM的标准化组织是W3C,BOM最初是Netscape浏览器标准的一部分。
window包括:document,location,navigation,screen,history
1.1、BOM的构成
window对象 是浏览器的顶级对象,它具有双重角色。
它是JS访问浏览器的一个接口。
它是一个全局对象定义一个全局作用域的变量、函数都会变成window对象的属性和方法。在调用的时候可以省略window,前面学习的对话框都属于window对象方法,如alert()、prompt()等。
**注意:**window下的一个特殊属性window.name
2、window对象的常见事件
window.onload = function(){}
或者
window.addEventListener("load",function(){});
1、window.onload是窗口(页面)加载事件,当文档内容完全加载完成会触发该事件(包括图像、脚本文件、CSS文件等)就调用的处理函数。
2、window.onload 传统注册事件只能写一次,如果有多个,会以最后一个window.onload为准。
3、如果使用addEventListener则没有限制。
2.1窗口加载事件:
document.addEventListener('DOMContentLoaded',function(){})
DOMContentLoaded事件触发时,仅当DOM加载完成,不包括样式表,图片,flash等等。(IE9以上支持)
如果页面的图片很多的话,从用户访问到onload触发可能需要较长的时间,交互效果就不能实现,必然影响用户的体验,此时用DOMContentLoaded事件比较适合。
2.2调整窗口大小事件
window.onresize = function(){}
wondow.addEventListener('resize',function(){})
window.onresize 是调整窗口大小的加载事件,当触发时就调用的处理函数。
注意:
只要窗口大小发生像素变化,就会触发这个事件。
我们经常利用这个事件完成响应式布局。window.innerWidth 当前屏幕宽度
3、定时器
window对象给我们提供2个非常好用的方法-定时器。
3.1 setTimeout()
window.setTimeout(调用函数,[延迟的毫秒数]);
<script>
window.addEventListener('load', function () {
// setTimeout语法规范: window.setTimeout('调用函数',延迟时间);
// 1、window在调用时可以省略
// 2、这个延迟时间单位是毫秒数,但是可以省略,如果不省略默认的是0
/* setTimeout(function () {
console.log('时间到了');
}, 2000); */
// 3、这个调用函数可以直接写函数 还可以写 函数名 还有一个写法 '函数名()'
// 4、页面中可能有很多的定时器,我们经常给定时器添加标识符用于区别不同的定时器 (名字)
function callback() {
console.log('爆炸了');
}
var timer1 = setTimeout(callback, 2000);
var timer2 = setTimeout(callback, 5000);
// setTimeout('callback()', 2000);//不提倡此写法
});
</script>
setTimeout() 方法用于设置一个定时器,该定时器在定时器到期后执行调用函数。
setTimeout() 这个调用函数我们也称为回调函数 callback
普通函数是按照代码顺序直接调用
而这个函数,需要等待时间,时间到了才会去调用这个函数,因此称为回调函数。
之前讲的 element.onclick = function(){} 或者 element.addEventListener(“click”,fn); 里面的 函数也是回调函数。
清除定时器:
window.clearTimeout(timeout ID):
clearTimeout()方法取消了先前的调用 setTimeout() 建立的定时器。
<script>
window.addEventListener('load', function () {
var btn = document.querySelector('button');
function callback() {
console.log('爆炸');
}
var timer = setTimeout(callback, 4000);
btn.addEventListener('click', function () {
// window可以省略 里面的参数就是定时器的标识符
window.clearTimeout(timer);
});
});
</script>
3.2 setInterval()
setInterval()方法重复调用一个函数,每隔这个时间,就去调用一次回调函数。
window.setInterval(回调函数,[间隔的毫秒数]);
<script>
window.addEventListener('load', function () {
/* 语法规范:setInterval(调用函数,延时时间) */
var timer = setInterval(function () {
console.log('傻逼');
}, 1000);
// setTimeout 延时时间到了就去调用这个函数,只调用一次就结束了这个定时器
// setInterval 每隔这个延时时间就会去调用一次函数,重复性的调用此函数
});
</script>
停止setInterval()定时器:
clearInterval()方法取消了先前通过setInterval()建立的定时器。
window.clearInterval(intervalID);
<body>
<script>
window.addEventListener('load', function () {
var begin = document.querySelector('.begin');
var stop = document.querySelector('.stop');
// 全局变量 null是一个空对象
var Timer = null;
begin.addEventListener('click', function () {
Timer = setInterval(function () {
console.log('大大的');
}, 1000);
});
stop.addEventListener('click', function () {
clearInterval(Timer);
});
});
</script>
<button class="begin">开启定时器</button>
<button class="stop">停止定时器</button>
</body>
3.3 this
this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,一般情况下this的最终指向的是那个调用它的对象。
4、JS执行机制
4.1 JS 是单线程
JS语言的一大特点就是单线程,也就是说,同一时间只能做一件事。这是因为JS这门脚本语言诞生的使命所致------JS是为处理页面中用户的交互,以及操作DOM而诞生的。比如我们对某个DOM元素进行添加和删除操作,不能同时进行。应该先进行添加,之后再删除。
单线程就意味着,所有的任务需要排队,前一个任务结束,才会执行后一个任务,这样导致的问题是:如果JS执行的时间过长,这样就会造成页面的渲染不连贯,导致页面渲染加载阻塞的感觉。
4.2 同步和异步
// 第一个问题
console.log(1);
setTimeout(function () {
console.log(3); //执行时间比较长
}, 1000);
console.log(2);
// 结果:1 2 3
为了解决这个问题,利用多核CPU的计算能力,HTML5提出Web Worker 标准,允许JS脚本创建多个线程。于是出现了同步和异步。
**同步:**前一个任务结束后再执行后一个任务,程序的执行顺序与任务的排列顺序是一致的,同步的。
**异步:**做一件事情的同时还可以做其他事情。
本质区别:在一条流水线上各个流程执行的顺序是不同的。
同步任务:同步任务都在主线程上执行,形成一条执行线。
**异步任务:**JS的异步是通过回调函数实现的。 一般而言,异步任务有以下三种类型:
-
普通事件,如click、resize等
-
资源加载,如load、error等
-
定时器,包括setInterval、setTimeout等
异步任务相关回调函数添加到任务队列中(任务队列也称消息队列)。
4.3 执行机制
先执行执行栈中的同步任务。
异步任务(回调函数)放入到任务队列中。
一旦执行栈中的所有同步任务执行完毕,系统就会按次序读取任务队列中的异步任务,于是被读取的异步任务结束等待状态,进入执行栈,开始执行。
5、location对象
window对象给我们提供了一个location属性用于获取或设置窗体的URL,并且可以用于解析URL。因为这个属性返回的是一个对象,所以我们将这个属性也称为location对象。
URL: 统一资源定位符(Uniform Resource Location,URL)是互联网上标准资源的地址。互联网上的每个文件都有一个唯一的URL,它包含的信息指出文件的位置以及浏览器应该怎么处理它。
URL的一般语法格式为:
protocol://host[:port]/path/[?query]#fragment
http://www.itcast,cn/index.html?name=andy&age=18#link
组成 | 说明 |
---|---|
protocol | 通信协议 常用的http,ftp,maito等 |
host | 主机( 域名)www.itheima.com |
port | 端口号 可选,省略时使用方案的默认端口 如http的默认端口为80 |
path | 路径 由 零或者多个’/'符号隔开的字符串,一般用来表示主机上一个目录或者文件地址 |
query | 参数 以键值对的形式,通过&符号分隔开来 |
fragment | 片段 #后面内容 常见于链接 锚点 |
5.1 location对象的属性
location对象属性 | 返回值 |
---|---|
location.href | 获取或者设置 整个URL |
location.host | 返回主机(域名)www.itheima.com |
location.port | 返回端口号 如果未返回 空字符串 |
location.pathname | 返回路径 |
location.search | 返回参数 |
location.hash | 返回片段 #后面内容 常见于链接 锚点 |
//login.html页面
<form action="index.html">
用户名:<input type="text" name="uname" />
<input type="submit" value="登录" />
</form>
//index.html页面
<body>
<div></div>
<script>
// console.log(location.search); //?uname=andy
// 1、先去掉?字符串截取 substring(start,end)
var params = location.search.substring(1);
console.log(params);//uname=andy
// 2、利用=把字符串分隔成为数组 split('=')
var arr = params.split('=');
console.log(arr); //['uname', 'andy']
var unameArr = arr[1];
var div = document.querySelector('div');
div.innerHTML = '欢迎' + unameArr + '进入';
</script>
</body>
5.2 location对象的方法
location对象方法 | 返回值 |
---|---|
location.assign() | 跟href一样,可以跳转页面(也称为重定向页面)记录历史 |
location.replace() | 替换当前页面,因为不记录历史,所以不能后退页面 |
location.reload() | 重新加载页面,相当于刷新按钮或者 F5 如果参数为true 强制刷新ctrl+f5 |
6、navigator对象
navigator对象包含有关浏览器的信息,它有很多属性,最常用的是userAgent,该属性可以返回有客户机发送服务器的user-agent头部的值。
下面前端代码判断用户那个终端打开页面,实现跳转。
if((navigator.userAgent.match(/(phone|pad|pod|iPhone|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i))) {
window.location.href = ''; // 手机端页面链接
} else {
window.location.href = ''; // PC端页面
}
7、history对象
window 对象给我们提供了一个history对象,与浏览器历史记录进行交互。该对象包含用户(在浏览器窗口中)访问过的URL。
history对象方法 | 作用 |
---|---|
back() | 可以后退功能 |
forward() | 前进功能 |
go(参数) | 前进后退功能 参数如果是1 前进一个页面 如果是-1 后退一个页面 |