zoukankan      html  css  js  c++  java
  • 私人定制javascript事件处理机制(浅谈)

    看到园子里关于事件监听发表的文章,我都有点不好意思写了。不过想想我的题目以私人定制作开头也就妥妥地写吧。

    事件相关概念

    1.事件类型 发生事件的字符串
      有传统事件类型 比如表单、window事件等
      DOM事件类型
      HTML5事件类型 drag、drop
      触摸屏和移动设备事件类型 例如touchmove
    2.事件目标 Window/Document/Element/XMLHttpRequest/...
    3.事件对象 与特定事件相关且包含有关事件详细信息的对象 就是大家熟悉的event
    4.事件传播 浏览器决定哪个对象触发其事件处理程序的过程 有冒泡阶段和处于阶段和捕获阶段

    注册事件处理程序

    1.设置事件目标的属性为所需事件处理程序函数
    例如dom1.onclick=function(){/*....*/};
    2.设置HTML标签属性为事件处理程序
    例如
    <p onclick='alert('我的小苹果');'/>
    但实际javascript引擎做了如下加工:相当于将作用域前置了,表示对with理解不是很深。

    function(event){
        with(document){
            with(this.form||{}){
                with(this){
                  /*这里是编码*/
                 }
            }
        }
    }                    

    最后给出的建议是:建议js代码与html分开,因为这样才符合html与javascript各自的职责

    事件处理程序的运行环境

    1.通过属性注册处理程序时,例如e.onclick=function(){/**/} this 是指事件目标对象
    2.对于attachEvent()此时的this指window对象 所以可以参考下列代码

    function addEvent(target,type,handler)
    {
      if(target.addEventListener)
        target.addEventListener(type,handler,false);
      else
        target.attachEvent("on"+type,
      function(event){
        return handler.call(target,event);
      });
    }

    事件处理程序的返回值
    很多返回值为false的可以阻止浏览器默认操作,比如链接的跳转,如果return false可以阻止跳转

    事件调用顺序

    1.通过设置对象属性或HTML属性注册的处理程序一直优先调用
    2.addEventListener()注册的处理程序按照它们的注册顺序调用
    3.attachEvent()注册的处理程序可能按照任何顺序调用
    谈到事件调用顺序,这里不得不说的就是
    DOM2级事件规定事件包含三个阶段
    1.事件捕获阶段
    2.处于目标阶段
    3.事件冒泡阶段
    此处借用http://www.cnblogs.com/yexiaochai/p/3567597.html的例子并膜拜其发现

    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
      <title></title>
      <style type="text/css">
        #p {  300px; height: 300px; padding: 10px; border: 1px solid black; }
        #c {  200px; height: 200px; border: 1px solid red; }
        #sub {  100px; height: 100px; border: 1px solid red; }
      </style>
    </head>
    <body>
      <div id="p">
        parent
        <div id="c">
          child
        </div>
      </div>
      <script type="text/javascript">
          window.alert = function (msg) {
              console.log(msg);
          };
          var p = document.getElementById('p'),
              c = document.getElementById('c');
          p.addEventListener('click', function (e) {
              alert('父节点冒泡')
          }, false);
          c.addEventListener('click', function (e) {
              alert('子节点捕获')
          }, true);
          c.addEventListener('click', function (e) {
              alert('子节点冒泡')
          }, false); 
          p.addEventListener('click', function (e) {
              alert('父节点捕获')
          }, true);
      </script>
    </body>
    </html>

    结果如下

    //父节点捕获
    //子节点捕获
    //子节点冒泡
    //父节点冒泡
    先按照DOM2执行但是如果到了2.处于阶段此时若绑定了捕获又绑定了冒泡那么按照注册顺序执行
    所以如果是下列代码

        p.addEventListener('click', function (e) {
              alert('父节点冒泡')
          }, false);
           c.addEventListener('click', function (e) {
              alert('子节点冒泡')
          }, false); 
          c.addEventListener('click', function (e) {
              alert('子节点捕获')
          }, true);
         
          p.addEventListener('click', function (e) {
              alert('父节点捕获')
          }, true);

    那么答案是多少呢?

    //父节点捕获
    //子节点冒泡
    //子节点捕获
    //父节点冒泡
    鼠标事件
    除了mouseenter和mouseleave外的所有鼠标事件都能冒泡

    事件取消

    通过事件对象(event)的preventDefault()/returnValue=false(IE)
    事件对象的stopPropagation()可以在事件传播的任何时间调用,无论是捕获阶段、事件目标本身中和冒泡阶段
    就是阻止事件的进一步传播,不管捕获也好还是冒泡也好
    /cancelBubble=true(IE)只能取消冒泡事件传播

    文档加载事件

    当文档加载解析完毕且有所延迟(deferred)脚本执行完毕时会触发DOMContentLoaded事件,此时图片和异步(async)脚本
    可能依旧在加载,但是文档已经为操作准备就绪了。

    在IE中,每次状态改变都伴随着Document.readystatechange事件
    那么document.readyState属性随着文档加载过程而变如果是complete则表示文档就绪
    这里readystatechange执行顺序早于DOMContentLoaded早于load
    但是readystatechange会多次轮询调用,我猜的没有验证。

    文档准备就绪封装的函数

    var whenReady = (function () {
              var funcs = [];
              var ready = false;
              function handler(e) {
                  if (ready) return;
                  //此处是为了readystatechange事件做的判断,如果document.readyState === "complete"说明所有的文档准备就绪包括图片
                  //和外部请求的资源的那个
                  if (e.type === "readystatechange" && document.readyState !== "complete") {
                      return;
                  }
                  for (var i = 0; i < funcs.length; i++) {
                      funcs[i].call(document);
                  }
                  ready = true;
                  funcs = null;
              };
              if (document.addEventListener) {
                  document.addEventListener("DOMContentLoaded", handler, false);
                  document.addEventListener("readystatechange", handler, false);
                  window.addEventListener("load", handler, false);
              }
              else if (document.attachEvent) {
                  document.attachEvent("onreadystatechange", handler);
                  window.attachEvent("onload", handler);
              }
              return function whenReady(f) {
                  if (ready) f.call(document);
                  else funcs.push(f);
              }
          }());
    
          function fn() {
              console.log("fn is exec");
          }
          document.addEventListener("DOMContentLoaded", fn, false);
          whenReady(fn);

    结束语

    事件处理调用机制,首先要了解3个阶段和一些常用的事件类型函数,毕竟前端js是事件驱动写法比较多,本人水平有限,如有错误,希望指出,如果对你有那么一点点帮助,请支持推荐一下。

  • 相关阅读:
    php静态调用非静态方法
    phalcon 框架3.0更新时报错
    centos7.5更换docker-ce镜像源
    腾讯云更换镜像源遇到的坑
    php cli模式下调试
    审查php.ini自动分析程序
    docker WARNING: IPv4 forwarding is disabled. Networking will not work.
    git常用命令,制作缩写命令
    学习GRPC(一) 简单实现
    mac与linux服务器之间使用ssh互通有无
  • 原文地址:https://www.cnblogs.com/miniyk/p/3828785.html
Copyright © 2011-2022 走看看