文章目录
事件
事件是由三部分组成:事件源、事件类型、事件处理程序,我们也称之为事件三要素。
1、事件源:事件被触发的对象,是指在哪个元素引发的事件。
<button id ="btn">程序猿</button>
var btn = document.getElementById('btn');
2、事件类型:如何触发、什么事件,比如鼠标点击(onclick)还是鼠标经过,还是键盘按下?
btn.onclick = function() {
alert('写代码');
}
3、事件处理程序(事件驱动程序):通过一个函数赋值的方式完成,即执行的结果。
<button id ="btn">程序猿</button>
var btn = document.getElementById('btn');
btn.onclick = function() {
alert('写代码');
}
一、事件冒泡:
事件的冒泡(Bubble):所谓的冒泡指的就是事件的向上传导,当后代元素上的事件被触发时,其祖先元素的相同事件也会被触发(即开始时由最具体的元素接收,然后逐级向上传播到到 DOM 最顶层节点),在开发中大部分情况冒泡都是有用的,如果不希望发生事件冒泡可以通过事件对象来取消冒泡: event.cancelBubble=true.
事件源 =>根节点(由内到外)进行事件传播,事件冒泡本身的特性,会带来的坏处,也会带来的好处,需要我们灵活掌握。
<head>
<title>事件冒泡</title>
<style>
#box1 {
width: 200px;
height: 200px;
background: pink;
}
#box2 {
width: 100px;
height: 100px;
background: blue;
}
#div1 {
width: 200px;
height: 200px;
background: red;
}
#div2 {
width: 100px;
height: 100px;
background: green;
}
</style>
</head>
<body>
<div id="box1">
我是父盒子
<div id="box2">
我是子盒子
</div>
</div>
<br>
<br>
<div id="div1">
我是父盒子
<div id="div2">
我是子盒子
</div>
</div>
<br>
<br>
<a href="https://www.runoob.com/js/js-htmldom-eventlistener.html" id="a">菜鸟教程</a>
<script>
// 案例演示1:创建两个div,叠放在一起,分别绑定单击事件,点击最里边的div,会触发两个div的单击事件
var box1 = document.getElementById("box1");
var box2 = document.getElementById("box2");
box1.onclick = function() {
console.log("box1 的单击事件触发了!");
};
box2.onclick = function() {
console.log("box2 的单击事件触发了!");
};
// 案例演示2:创建两个div,叠放在一起,分别绑定单击事件,点击最里边的div,不会触发两个div的单击事件,只会触发自己的单击事件,这时候我们可以取消事件冒泡
var div1 = document.getElementById("div1");
var div2 = document.getElementById("div2");
div1.onclick = function() {
console.log("div1 的单击事件触发了!");
stopBubble();
};
div2.onclick = function() {
console.log("div2 的单击事件出发了!");
stopBubble();
};
function stopBubble(event) {
if (event && evemt.stopPropagation) {
event.stopPropagation();
} else {
window.event.cancelBubble = true;
}
}
// 案例演示3:当点击a标签的时候,阻止a标签的默认跳转事件,采用事件阻止
var a = document.getElementById("a");
a.onclick = function() {
stopDefault();
};
function stopDefault(event) {
if (event && event.preventDefault) {
event.preventDefault();
} else {
window.event.returnValue = false;
}
return false;
}
</script>
</body>
阻止事件冒泡的两种方法:
if(e && e.stopPropagation){
//标准写法:利用事件对象里面的 stopPropagation()方法
e.stopPropagation();
}else{
//非标准写法:IE 6-8 利用事件对象 cancelBubble 属性
window.event.cancelBubble = true;
}
二、事件绑定:
我们以前绑定事件代码只能一个事件绑定一个函数,那我们要是想一个事件对应多个函数,并且不存在兼容性的问题该如何解决呢?
//方式一:在DOM元素中直接绑定。but在DOM结构如果绑定两个 "onclick" 事件,只会执行第一个。
<div id="btn" onclick="clickone()" onclick="clicktwo()"></div>
<script>
function clickone(){ alert("hello"); } //执行这个
function clicktwo(){ alert("world!"); }
</script>
//方式二:在Javascript代码中绑定。这种绑定方式只能给一个事件绑定一个处理函数,在脚本通过匿名函数的方式绑定的只会执行最后一个事件。
<div id="btn"></div>
<script>
document.getElementById("btn").onclick = function(){ alert("hello"); }
document.getElementById("btn").onclick = function(){ alert("world"); } //执行这个
</script>
//方式三:绑定事件监听函数。可以绑定多次同一个事件,且都会执行。
<div id="btn"></div>
<script>
document.getElementById("btn").addeventlistener("click",clickone,false);
function clickone(){ alert("hello"); } //先执行
document.getElementById("btn").addeventlistener("click",clicktwo,false);
function clicktwo(){ alert("world"); } //后执行
</script>
解决事件绑定兼容问题:
/*为元素绑定事件兼容性代码*/
function addEventListener(element, type, fn) {
if(element.addEventListener) {
element.addEventListener(type, fn, false);
} else if(element.attachEvent) {
element.attachEvent("on" + type, fn);
} else {
element["on" + type] = fn;
}
}
/*为元素解绑事件兼容性代码*/
function removeEventListener(element, type, fnName) {
if(element.removeEventListener) {
element.removeEventListener(type, fnName, false);
} else if(element.detachEvent) {
element.detachEvent("on" + type, fnName);
} else {
element["on" + type] = null;
}
}
三、事件委派:
事件委派,就拿我之前看过的一个例子来说,同公司的小明,小红,小蓝三个人预计在下周一有快递要签收,但是呢三个人都等在公司楼下签收快递不太好,于是就委托公司前台小美代为签收一下。
这个例子中,三人共同事件统一绑定给同一人前台小美,这样当三人快递到达时触发了取快递的事件,事件会一直冒泡传递,召唤前台小美代签快递。
<head>
<title>67.事件委派</title>
</head>
<body>
<ul id="ul">
<li><a href="#" class="link">小明快递</a></li>
<li><a href="#" class="link">小红快递</a></li>
<li><a href="#" class="link">小蓝快递</a></li>
</ul>
<script>
// 案例演示:为ul列表中的所有a标签都绑定单击事件
var ul = document.getElementById("ul");
ul.onclick = function(event) {
event = event || window.event;
if (event.target.className == "link") {
console.log("快递到了,召唤小美!");
}
};
</script>
</body>
四、事件传播:
事件的传播:关于事件的传播网景公司和微软公司有不同的理解。
— 微软公司认为事件应该是由内向外传播,也就是当事件触发时,应该先触发当前元素上的事件,然后再向当前元素的祖先元素上传播,也就说事件应该在冒泡阶段执行。
— 网景公司认为事件应该是由外向内传播的,也就是当前事件触发时,应该先触发当前元素的最外层的祖先元素的事件,然后在向内传播给后代元素。
— W3C综合了两个公司的方案,将事件传播分成了三个阶段:
- 捕获阶段:在捕获阶段时从最外层的祖先元素,向目标元素进行事件的捕获,但是默认此时不会触发事件。
- 目标阶段:事件捕获到目标元素,捕获结束开始在目标元素上触发事件。
- 冒泡阶段:事件从目标元素向它的祖先元素传递,依次触发祖先元素上的事件。
注意:如果希望在捕获阶段就触发事件,可以将addEventListener()的第三个参数设置为true,一般情况下我们不会希望在捕获阶段触发事件,所以这个参数一般都是false,并且注意,IE8及以下的浏览器中没有捕获阶段,我们可以使用event.stopPropagation();取消事件传播。
五、事件捕获:
网景提出了另一种事件流名为事件捕获(event capturing)。与事件冒泡相反,事件捕获的事件流是从最外层开始发生,直到被触发的具体元素。当鼠标点击或者触发dom事件时(被触发dom事件的这个元素被叫作事件源),浏览器会从根节点=>事件源(由外到内)进行事件传播。
代码如下:
<head>
<title>事件捕获</title>
<style>
.red{
width: 300px;
height: 300px;
background-color: red;
}
.yellow{
width: 200px;
height: 200px;
margin-left: 300px;
background-color: yellow;
}
.green{
width: 100px;
height: 100px;
margin-left: 200px;
background-color: green;
}
</style>
</head>
<body>
<div class="red">
<div class="yellow">
<div class="green"></div>
</div>
</div>
<script>
var red = document.getElementsByClassName('red')[0],
yellow = document.getElementsByClassName('yellow')[0],
green = document.getElementsByClassName('green')[0];
red.addEventListener('click',function(){
console.log('red')
},true)
yellow.addEventListener('click',function(){
console.log('yellow')
},true)
green.addEventListener('click',function(){
console.log('green')
},true)
</script>
</body>
</html>
上述代码中,如果在事件捕获的情况下,触发green的click事件的顺序应该是:document->html->body->red->yellow->green
this指向
- 以函数形式调用时,this永远都是window
- 以方法的形式调用时,this是调用方法的对象
- 以构造函数的形式调用时,this是新创建的那个对象
- 使用call和apply调用时,this是传入的那个指定对象
1、函数调用
当一个函数并非一个对象的属性时,那么它就是被当做函数来调用的。在此种模式下,this被绑定为全局对象,在浏览器环境下就是window对象。
<script>
function people() {
var name = '小明';
console.log(this.name);
console.log(this);
}
people();
</script>
2、方法调用
当函数被保存为一个对象的属性时,它就可称为这个对象的方法。当一个方法被调用时,this被绑定到这个对象上。如果调用表达式包含一个提取属性的动作(.或 []),那么它被称为方法调用。
<script>
var people = {
name:'小明',
sayName:function() {
console.log(this.name);
}
}
people.sayName();
</script>
3、构造函数调用
在构造函数new出一个对象时,this指向这个构造函数,new关键字会改变this的指向。
<script>
function People() {
console.log(this);
}
var xm = new People();
</script>
<script>
function People() {
this.name = '小明';
}
var xm = new People();
console.log(xm.name);
</script>
4、call和apply调用
JS中,函数也是对象,所有函数对象都有两个方法:apply和call,这两个方法可以让我们构建一个参数数组传递给调用函数,也允许我们改变this的值。
<script>
let obj1={
name:"xm",
fn(){
console.log(this.name)
}
}
let obj2={
name:"xh",
fn(){
console.log(this.name)
}
}
obj1.fn.call(obj2)
</script>
数组和字符串互相转换
1、数组转字符串
<script>
var a,b;
a = new Array(0,1,2,3,4);
b = a.join("-");
console.log("a:"+a);
console.log("b:"+b);
</script>
2、字符串转数组
<script>
var s = "abc,abcd,aaa";
ss = s.split(",");// 在每个逗号(,)处进行分解 ["abc", "abcd", "aaa"]
console.log("ss:"+ss);
var s1 = "helloworld";
ss1 = s1.split(''); //["h", "e", "l", "l", "o", "w", "o", "r", "l", "d"]
console.log("s1:"+s1);
</script>