From fbb8c34468d120d02b3d76a48ae3c1ea9d5138ad Mon Sep 17 00:00:00 2001 From: qianguyihao Date: Tue, 12 Nov 2019 16:56:33 +0800 Subject: [PATCH] =?UTF-8?q?update:=20=E4=BA=8B=E4=BB=B6=E5=86=92=E6=B3=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 04-JavaScript基础/20-正则表达式.md | 7 +- ...8-事件的冒泡.md => 28-事件捕获和事件冒泡.md} | 177 ++++++++++-------- 04-JavaScript基础/29-事件委派.md | 65 +++++++ 3 files changed, 162 insertions(+), 87 deletions(-) rename 04-JavaScript基础/{28-事件的冒泡.md => 28-事件捕获和事件冒泡.md} (51%) create mode 100644 04-JavaScript基础/29-事件委派.md diff --git a/04-JavaScript基础/20-正则表达式.md b/04-JavaScript基础/20-正则表达式.md index 02c821b..479018a 100644 --- a/04-JavaScript基础/20-正则表达式.md +++ b/04-JavaScript基础/20-正则表达式.md @@ -191,12 +191,10 @@ ### split() -`split()`:将一个字符串拆分成一个数组。 +`split()`:将一个字符串拆分成一个数组。可以接受一个正则表达式作为参数。 备注:关于`split()`更详细的用法,可以看之前的关于《内置对象:String》这篇文章。 -`split()`方法可以接受一个正则表达式作为参数。 - **正则相关的举例**:根据任意字母,将字符串拆分成数组。 代码实现:(通过正则) @@ -204,7 +202,7 @@ ```javascript var str = "1a2b3c4d5e6f7g"; - var result = str.split(/[A-z]/); // 参数是一个正则表达式:表示所有字符 + var result = str.split(/[A-z]/); // 参数是一个正则表达式:表示所有字母 console.log(result); ``` @@ -231,7 +229,6 @@ console.log(result); // 打印结果:6 ``` - ### match() `match()`:根据正则表达式,从一个字符串中将符合条件的内容提取出来,封装到一个数组中返回(即使只查询到一个结果)。 diff --git a/04-JavaScript基础/28-事件的冒泡.md b/04-JavaScript基础/28-事件捕获和事件冒泡.md similarity index 51% rename from 04-JavaScript基础/28-事件的冒泡.md rename to 04-JavaScript基础/28-事件捕获和事件冒泡.md index 20c8f12..f7dbe8a 100644 --- a/04-JavaScript基础/28-事件的冒泡.md +++ b/04-JavaScript基础/28-事件捕获和事件冒泡.md @@ -4,11 +4,11 @@ 事件传播的三个阶段是:事件捕获、事件冒泡和目标。 -- 事件捕获阶段:事件从最上一级标签开始往下查找,直到捕获到事件目标 target。(从祖先元素往子元素查找,DOM树结构)。在这个过程中,事件相应的监听函数是不会被触发的。 +- 事件捕获阶段:事件从祖先元素往子元素查找(DOM树结构),直到捕获到事件目标 target。在这个过程中,事件相应的监听函数是不会被触发的。 - 事件目标:当到达目标元素之后,执行目标元素该事件相应的处理函数。如果没有绑定监听函数,那就不执行。 -- 事件冒泡阶段:事件从事件目标 target 开始,往上冒泡直到页面的最上一级标签。(从子元素到祖先元素冒泡) +- 事件冒泡阶段:事件从事件目标 target 开始,从子元素往冒泡祖先元素冒泡,直到页面的最上一级标签。 如下图所示: @@ -16,7 +16,6 @@ PS:这个概念类似于 Android 里的 **touch 事件传递**。 - ### 事件捕获 addEventListener可以捕获事件: @@ -32,7 +31,7 @@ addEventListener可以捕获事件: 代码演示: ```javascript - //参数为true,代表捕获;参数为false或者不写参数,代表冒泡 + //参数为true,代表事件在「捕获」阶段触发;参数为false或者不写参数,代表事件在「冒泡」阶段触发 box3.addEventListener("click", function () { alert("捕获 child"); }, true); @@ -54,15 +53,11 @@ addEventListener可以捕获事件: ![](http://img.smyhvae.com/20180204_1101.gif) +(如果上面的图片打不开,请点击:) -**说明**:捕获阶段,事件依次传递的顺序是:window --> document --> html--> body --> 父元素、子元素、目标元素。 +**重点**:捕获阶段,事件依次传递的顺序是:window --> document --> html--> body --> 父元素、子元素、目标元素。 -PS1:第一个接收到事件的对象是 **window**(有人会说body,有人会说html,这都是错误的)。 - -PS2:JS中涉及到DOM对象时,有两个对象最常用:window、doucument。它们俩也是最先获取到事件的。 - - -事件捕获阶段的完整写法是: +这几个元素在事件捕获阶段的完整写法是: ```javascript window.addEventListener("click", function () { @@ -91,6 +86,11 @@ PS2:JS中涉及到DOM对象时,有两个对象最常用:window、doucument ``` +说明: + +(1)第一个接收到事件的对象是 **window**(有人会说body,有人会说html,这都是错误的)。 + +(2)JS中涉及到DOM对象时,有两个对象最常用:window、doucument。它们俩是最先获取到事件的。 **补充一个知识点:** @@ -102,16 +102,11 @@ PS2:JS中涉及到DOM对象时,有两个对象最常用:window、doucument 二者不要混淆了。 - - - - ### 事件冒泡 **事件冒泡**: 当一个元素上的事件被触发的时候(比如说鼠标点击了一个按钮),同样的事件将会在那个元素的所有**祖先元素**中被触发。这一过程被称为事件冒泡;这个事件从原始元素开始一直冒泡到DOM树的最上层。 - -通俗来讲,冒泡指的是:**子元素的事件被触发时,父盒子的同样的事件也会被触发**。取消冒泡就是取消这种机制。 +通俗来讲,冒泡指的是:**子元素的事件被触发时,父元素的同样的事件也会被触发**。取消冒泡就是取消这种机制。 代码演示: @@ -137,7 +132,9 @@ PS2:JS中涉及到DOM对象时,有两个对象最常用:window、doucument ![](http://img.smyhvae.com/20180204_1028.gif) -上图显示,当我点击儿子 box3的时候,它的父亲box2、box1、body都依次被触发了。即使我改变代码的顺序,也不会影响效果的顺序。 +(如果上面的图片打不开,请点击:) + +上图显示,当我点击子元素 box3 的时候,它的父元素box2、box1、body都依次被触发了。即使我改变代码的顺序,也不会影响效果的顺序。 当然,上面的代码中,我们用 addEventListener 这种 DOM2的写法也是可以的,但是第三个参数要写 false,或者不写。 @@ -170,10 +167,14 @@ IE6.0: alert("冒泡 child"); event = event || window.event; - console.log(event.bubbles); //打印结果:true + console.log(event.bubbles); //打印结果:true。说明 onclick 事件是可以冒泡的 } ``` +## 阻止冒泡 + +大部分情况下,冒泡都是有益的。当然,如果你想阻止冒泡,也是可以的。可以按下面的方法阻止冒泡。 + ### 阻止冒泡的方法 w3c的方法:(火狐、谷歌、IE11) @@ -208,74 +209,86 @@ event.cancelBubble = true 上方代码中,我们对box3进行了阻止冒泡,产生的效果是:事件不会继续传递到 father、grandfather、body了。 -## 事件委托 - -事件委托,通俗地来讲,就是把一个元素响应事件(click、keydown......)的函数委托到另一个元素。 - -比如说有一个列表 ul,列表之中有大量的列表项 li: +### 阻止冒泡的举例 ```html -
    -
  • Item 1
  • -
  • Item 2
  • -
  • Item 3
  • -
  • Item 4
  • -
  • Item 5
  • -
  • Item 6
  • -
+ + + + + + + + + + +
+
+ + ``` +效果演示: -当我们的鼠标移到Li上的时候,需要获取此Li的相关信息并飘出悬浮窗以显示详细信息,或者当某个Li被点击的时候需要触发相应的处理事件。我们通常的写法,是为每个Li都绑定类似onMouseOver或者onClick之类的事件监听: - - -```javascript - //每个 li 中做的事情 - function addListeners4Li(liNode){ - liNode.onclick = function clickHandler(){...}; - liNode.onmouseover = function mouseOverHandler(){...} - } - - window.onload = function(){ - var ulNode = document.getElementById("parent-list"); - var liNodes = ulNode.getElementByTagName("Li"); - for(var i=0, l = liNodes.length; i < l; i++){ - addListeners4Li(liNodes[i]); - } - } -``` - -但是,上面的做法会消耗内存和性能。 - - -因此,比较好的方法就是把这个点击事件绑定到他的父层,也就是 `ul` 上,然后在执行事件的时候再去匹配判断目标元素。如下: - - - -```javascript - // 获取父节点,并为它注册click事件。 false 表示事件在冒泡阶段触发(默认) - document.getElementById("parent-list").addEventListener("click", function (e) { - // event.target 代表的是子元素。toUpperCase()方法 指的是转换为大写字母并返回 - if (e.target && e.target.nodeName.toUpperCase() == "LI") { - // 真正的处理过程在这里 - console.log("List item ", e.target.id, " was clicked!"); - } - }, false); - -``` - - -上方代码,为父节点注册click事件,当子节点被点击的时候,click事件会从子节点开始**向上冒泡**。**父节点捕获到事件**之后,开始执行方法体里的内容:通过判断 e.target 拿到了被点击的子节点li。从而可以获取到相应的信息,并作处理。 - -换而言之,事件是在父节点上注册的,参数为false,说明事件是在冒泡阶段触发(往上传递),那就只有父节点能拿到事件,子节点是不可能拿到事件的。 - -所以事件委托可以减少大量的内存消耗,提高效率。 - -事件委托的参考链接: - -- [荐 | JavaScript事件代理和委托(Delegation)](https://www.cnblogs.com/owenChen/archive/2013/02/18/2915521.html) - -- [JavaScript 事件委托详解](https://zhuanlan.zhihu.com/p/26536815) +![](http://img.smyhvae.com/20191112_1650.gif) diff --git a/04-JavaScript基础/29-事件委派.md b/04-JavaScript基础/29-事件委派.md new file mode 100644 index 0000000..6c578be --- /dev/null +++ b/04-JavaScript基础/29-事件委派.md @@ -0,0 +1,65 @@ + +## 事件委托 + +事件委托,通俗地来讲,就是把一个元素响应事件(click、keydown......)的函数委托到另一个元素。 + +比如说有一个列表 ul,列表之中有大量的列表项 li: + +```html +
    +
  • Item 1
  • +
  • Item 2
  • +
  • Item 3
  • +
  • Item 4
  • +
  • Item 5
  • +
  • Item 6
  • +
+``` + +当我们的鼠标移到Li上的时候,需要获取此Li的相关信息并飘出悬浮窗以显示详细信息,或者当某个Li被点击的时候需要触发相应的处理事件。我们通常的写法,是为每个Li都绑定类似onMouseOver或者onClick之类的事件监听: + +```javascript + //每个 li 中做的事情 + function addListeners4Li(liNode){ + liNode.onclick = function clickHandler(){...}; + liNode.onmouseover = function mouseOverHandler(){...} + } + + window.onload = function(){ + var ulNode = document.getElementById("parent-list"); + var liNodes = ulNode.getElementByTagName("Li"); + for(var i=0, l = liNodes.length; i < l; i++){ + addListeners4Li(liNodes[i]); + } + } +``` + +但是,上面的做法会消耗内存和性能。 + +因此,比较好的方法就是把这个点击事件绑定到他的父层,也就是 `ul` 上,然后在执行事件的时候再去匹配判断目标元素。如下: + +```javascript + // 获取父节点,并为它注册click事件。 false 表示事件在冒泡阶段触发(默认) + document.getElementById("parent-list").addEventListener("click", function (e) { + // event.target 代表的是子元素。toUpperCase()方法 指的是转换为大写字母并返回 + if (e.target && e.target.nodeName.toUpperCase() == "LI") { + // 真正的处理过程在这里 + console.log("List item ", e.target.id, " was clicked!"); + } + }, false); + +``` + + +上方代码,为父节点注册click事件,当子节点被点击的时候,click事件会从子节点开始**向上冒泡**。**父节点捕获到事件**之后,开始执行方法体里的内容:通过判断 e.target 拿到了被点击的子节点li。从而可以获取到相应的信息,并作处理。 + +换而言之,事件是在父节点上注册的,参数为false,说明事件是在冒泡阶段触发(往上传递),那就只有父节点能拿到事件,子节点是不可能拿到事件的。 + +所以事件委托可以减少大量的内存消耗,提高效率。 + +事件委托的参考链接: + +- [荐 | JavaScript事件代理和委托(Delegation)](https://www.cnblogs.com/owenChen/archive/2013/02/18/2915521.html) + +- [JavaScript 事件委托详解](https://zhuanlan.zhihu.com/p/26536815) +