zoukankan      html  css  js  c++  java
  • JavaScript快速入门笔记(11):事件处理

    本系列随笔是本人的学习笔记,初学阶段难免会有理解不当之处,错误之处恳请指正。转载请注明出处:https://www.cnblogs.com/itwhite/p/12254884.html

    注册事件处理程序

    JavaScript 支持多种注册事件处理程序的方法:

    1. 设置 HTML 元素标签属性值为事件处理程序代码,例如:<button onclick="clickOk()">Ok</button>。
    2. 设置目标对象(比如:window 对象,某个 button 对象等)属性值为事件处理程序,例如:btn.onclick = function(){...}。
    3. 通过 addEventListener() 方法为某个目标对象添加事件处理程序,例如:btn.addEventListener("click", function(){...}, false)。其中:
      • 第一个参数为事件类型(字符串)
      • 第二个参数为函数对象,表明事件发生时应该调用的对象
      • 第三个参数通常使用 false 即可(即事件使用冒泡法传播,与之相对的是“捕获法”,后续会有详细描述)

    完整示例:

    <p id="number">0</p>
    <button onclick="add(event)">Add</button>    <!-- 1. 设置 HTML 元素标签属性值为事件处理程序代码 -->
    <button id="dec">Dec</button>
    <button id="reset">Reset</button>
    <script>
        var n = 0;
        var p = document.getElementById("number");
        var d = document.getElementById("dec");
        var r = document.getElementById("reset");
        d.onclick = dec;                           // 2. 设置目标对象属性值为事件处理程序,调用 dec() 时会自动传入事件对象
        r.addEventListener("click", reset, false); // 3. 通过 addEventListener() 方法添加事件处理程序,调用 reset() 时也会自动传入事件参数
        function add(event) {   // 这个函数中的 this 指向 window 对象,因为使用的是函数调用方式
            n++;   p.innerHTML = n;
        }
        function dec(event) {   // 这个函数中的 this 指向目标对象(即第二个<button>)
            n--;   p.innerHTML = n;
        }
        function reset(event) { // 这个函数中的 this 也指向目标对象(即第三个<button>)
            n = 0; p.innerHTML = n;
        }
    </script>

    事件传播

    事件传播是在父子(元素)对象之间进行的,比如:一个表单中有多个输入框,我们可以为每个输入框设置 change 事件处理程序,当然我们也可能会希望仅为表单自身设置 change 事件处理程序(来处理所有输入框 change 事件),这就需要输入框发生 change 事件时通知表单,通知表单的这个过程就叫“事件传播”。

    由于历史原因,Microsoft 和 Netscape 的浏览器在处理事件传播时使用两种不同的传递顺序(前者自顶向下,传递过程称为事件捕获;后者自底向上,传递过程称为冒泡法传递) ,大致流程如下图所示:

    为了折中这两种事件传播方式,主流的浏览器将事件传播分为两个阶段:

    • 第一阶段:按照事件捕获的顺序调用注册的捕获函数(addEventListener() 第三个参数设置为 true)
    • 第二阶段:按照冒泡法的顺序调用注册的处理函数(addEventListener() 第三个参数设置为 false)

    示例:

    <!DOCTYPE html>
    <html>
      <body>
        <button id="test">Test</button>
        <script>
          var btn = document.getElementById("test");
          var html = document.documentElement;
          var body = document.body;
          window.addEventListener("click", function(){console.log("Captured by window")}, true);
          window.addEventListener("click", function(){console.log("Bubble up to window")}, false);
          document.addEventListener("click", function(){console.log("Captured by document")}, true);
          document.addEventListener("click", function(){console.log("Bubble up to document")}, false);
          html.addEventListener("click", function(){console.log("Captured by <html>")}, true);
          html.addEventListener("click", function(){console.log("Bubble up to <html>")}, false);
          body.addEventListener("click", function(){console.log("Captured by <body>")}, true);
          body.addEventListener("click", function(){console.log("Bubble up to <body>")}, false);
          btn.addEventListener("click", function(){console.log("Captured by <button>")}, true);
          btn.addEventListener("click", function(){console.log("Bubble up to <button>")}, false);
        </script>
      </body>
    </html>
    <!-- 上述程序在控制台中输出以下内容:
        Captured by window
        Captured by document
        Captured by <html>
        Captured by <body>
        Captured by <button>    <=== 《JavaScript权威指南(第六版)》17.3.6节中说它不会被调用,Chrome中测试会被调用
        Bubble up to <button>
        Bubble up to <body>
        Bubble up to <html>
        Bubble up to document
        Bubble up to window
    -->

     取消浏览器默认操作和阻止事件传播

    上面第一节“注册事件处理程序”中介绍了三种方法,其中 方法1 和 方法2 可以通过返回 false 来取消浏览器默认操作,例如:在表单元素的 submit 事件处理程序中返回 false,就会阻止表单提交。示例:

    <!-- 示例一:通过 HTML 属性值返回 false 取消浏览器默认行为 -->
    <form onsubmit="alert('Stop submit'); return false">
        Name:     <input type="input" name="user" value="Jack" /><br />
        Password: <input type="password" name="password" value="123456" /><br />
        <button type="submit">Login</button>
    </form>
    
    <!-- 示例二:通过在事件处理函数(仅用于通过对象属性设置的)中返回 false 取消浏览器默认行为 -->
    <form>
        Name:     <input type="input" name="user" value="Jack" /><br />
        Password: <input type="password" name="password" value="123456" /><br />
        <button type="submit">Login</button>
    </form>
    <script>
        document.forms[0].onsubmit = function() {
            alert('Stop submit');
            return false;
        };
    </script>
    View Code

    注意:通过返回 false 阻止浏览器默认操作的行为,仅限于通过 方法1 和 方法2 (即通过 HTML 元素或对象 属性注册的事件处理函数)。

    通过 方法3 (即调用 addEventListener())注册的事件处理函数,可以通过事件对象的 preventDefault() 方法来阻止浏览器的默认操作(但它不会阻止事件传播),示例如下:

    <!-- 示例三:通过 addEventListener() 注册的事件处理函数,调用事件对象的 preventDefault() -->
    <form>
        Name:     <input type="input" name="user" value="Jack" /><br />
        Password: <input type="password" name="password" value="123456" /><br />
        <button type="submit">Login</button>
    </form>
    <script>
        document.forms[0].addEventListener("submit", function(e) {
            alert('Stop submit');
            e.preventDefault(); // 这里能阻止浏览器默认行为(即“提交”行为),但是不会阻止事件传播
        }, false);
        document.addEventListener("submit", function(e) {
            alert('The document object received the submit event'); // 这里会被调用,说明没有阻止事件传播
        }, false);
    </script>
    View Code

    要同时阻止事件传播,可以在调用了 preventDefault() 方法的基础上,同时调用事件对象的 stopPropagation() 方法,例如:

    <!-- 示例四:阻止浏览器默认行为,同时阻止事件传播 -->
    <form>
        Name:     <input type="input" name="user" value="Jack" /><br />
        Password: <input type="password" name="password" value="123456" /><br />
        <button type="submit">Login</button>
    </form>
    <script>
        document.forms[0].addEventListener("submit", function(e) {
            alert('Stop submit');
            e.preventDefault();  // 这里能阻止浏览器默认行为(即“提交”行为)
            e.stopPropagation(); // 阻止事件传播
        }, false);
        document.addEventListener("submit", function(e) {
            alert('The document object received the submit event'); // 这里不会被调用,说明阻止了事件传播
        }, false);
    </script>
    View Code

    注:在 Stackoverflow 问答帖子中(比如:https://stackoverflow.com/questions/30473581/when-to-use-preventdefault-vs-return-false)一些人说上面的 return false 相当于同时调用了 preventDefault() 和 stopPropagation() 方法,但个人在 Chrome 中测试 return false 并不会阻止事件传播。

    完。

  • 相关阅读:
    字符串和正则表达式
    委托和事件
    集合
    C#基础
    Pwnable中的passcode解题记录:
    DevExpress插件中GridView控件界面显示风格的保存与加载
    地区代码表(利用Hashtable实现)
    关于DevExpress插件中LookUpEdit控件的快速搜索列的定位问题
    C#实现PictureBox控件的动态添加及在每个图像左上角添加一个复选框
    Android4.4新的特性,在应用内开启透明状态栏和透明虚拟按钮。
  • 原文地址:https://www.cnblogs.com/itwhite/p/12254884.html
Copyright © 2011-2022 走看看