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 并不会阻止事件传播。

    完。

  • 相关阅读:
    什么是 bean 的自动装配?
    什么是 Spring 的内部 bean?
    什么是 Spring 的 MVC 框架?
    Spring AOP and AspectJ AOP 有什么区别?
    解释 JDBC 抽象和 DAO 模块?
    volatile 类型变量提供什么保证?
    一个 Spring Bean 定义 包含什么?
    什么是 Spring MVC 框架的控制器?
    使用 Spring 访问 Hibernate 的方法有哪些?
    什么是 Callable 和 Future?
  • 原文地址:https://www.cnblogs.com/itwhite/p/12254884.html
Copyright © 2011-2022 走看看