• 浏览器-js兼容性


    IE和Chrome下绑定事件处理方式:

    IE:attachEvent(‘onresize’,function);

    Chrome: addEventListener(resize,funtion,false);

    事件处理兼容性解决方法:

    if(window.attachEvent){window.attachEvent('onresize',function(){setTimeout('wMask.winResized();',50);});window.attachEvent('onunload',function(){wMask =null;});}
    else{ window.addEventListener('resize',function(){setTimeout('wMask.winResized();',50);},false);window.addEventListener(function(){wMask =null;},'unload',false);}
    相应的解绑:

    IE: detachEvent( '事件名' ,函数)

    Chrome: removeEventListener( '事件名' , 函数, 布尔值) 布尔值: [ true表示在事件捕获阶段执行 , false表示在事件冒泡阶段执行 ]

    jQuery下事件绑定机制:

    从jQuery1.7开始,jQuery引入了全新的事件绑定机制,on()和off()两个函数统一处理事件绑定。因为在此之前有bind(), live(), delegate()等方法来处理事件绑定,jQuery从性能优化以及方式统一方面考虑决定推出新的函数来统一事件绑定方法并且替换掉以前的方法。

    替换bind()
    当第二个参数'selector'为null时,on()和bind()其实在用法上基本上没有任何区别了,所以我们可以认为on()只是比bind()多了一个可选的'selector'参数

    $('a').bind('click', myHandler);
    $('a').on('click', myHandler);
    $(window).unbind('scroll.myPlugin');
    $(window).off('scroll.myPlugin');
    替换live()
    在1.4之前相信大部分非常喜欢使用live(),因为它可以把事件绑定到当前以及以后添加的元素上面,当然在1.4之后delegate()也可以做类似的事情了。live()的原理很简单,它是通过document进行事件委派的,因此也可以使用on()通过将事件绑定到document来达到live()一样的效果。

    live()写法

    代码如下:
    $('#list li').live('click', '#list li', function() {
    //function code here.
    });
    on()写法

    代码如下:
    $(document).on('click', '#list li', function() {
    //function code here.
    });
    这里的关键就是第二个参数'selector'在起作用了。它是一个过滤器的作用,只有被选中元素的后代元素才会触发事件。

    替换delegate()
    delegate()是1.4引入的,目的是通过祖先元素来代理委派后代元素的事件绑定问题,某种程度上和live()有点相似。只不过live()是通过document元素委派,而delegate则可以是任意的祖先节点。使用on()实现代理的写法和delegate()基本一致。

    delegate()的写法

    代码如下:
    $('#list').delegate('li', 'click', function() {
    //function code here.
    });
    on()写法

    代码如下:
    $('#list').on('click', 'li', function() {
    //function code here.
    });
    区别是第一个和第二个参数的顺序颠倒了一下,别的基本一样。

    1)jQuery1.7后 on事件绑定的方式:

    $( "elem" ).on( events, [selector], [data], handler );

    events:事件名称,可以是自定义事件名称

    selector:选择器

    data:事件触发时传递给事件处理函数

    handler:事件处理函数

    2)on方法源码分析

    on: function( types, selector, data, fn, /INTERNAL/ one ) {
      var origFn, type;

      // 如果types是对象,则说明是传入了多个事件
      if ( typeof types === "object" ) {
        // 如果selector不是string,则说明用户没有传入selector
        if ( typeof selector !== "string" ) {
          // 把selector赋值给data
          data = data || selector;

          // selector置为undefined
          selector = undefined;
        }

        // 遍历types对象中的每一个元素,并递归调用自身
        for ( type in types ) {
          this.on( type, selector, data, types[ type ], one );
        }
        return this;
      }

      // 如果data和fn都为null,说明用户只传了前两个参数

      if ( data == null && fn == null ) {
        // 把selector(第二个参数)赋值给fn
        fn = selector;

        // data和selector置为undefined
        data = selector = undefined;

      // 如果fn为null,说明用户传了三个参数
      } else if ( fn == null ) {

        // 如果selector的类型是string,说明用户没传data
        if ( typeof selector === "string" ) {
          // 把data赋值给fn
          fn = data;

          // 把data置为undefined
          data = undefined;
        } else {
          // 否则的话,说明用户没传selector,而是传了data,将data赋值给fn

          fn = data;

          // 将selector赋值给data
          data = selector;

          // 将selector置为undefined
          selector = undefined;
        }
      }

      // 如果用户传入的事件处理函数是false值,则将事件处理函数赋值为jQuery内部的returnFalse函数
      if ( fn === false ) {
        fn = returnFalse;

      // 如果用户没传回调函数,返回this,this是啥?返回this干嘛?
      } else if ( !fn ) {
        return this;
      }

      // 如果one为1,内部用,只绑定一次,暂时没看到用途

      if ( one === 1 ) {
        origFn = fn;
        fn = function( event ) {
          // Can use an empty set, since event contains the info
          jQuery().off( event );
          return origFn.apply( this, arguments );
        };
        // Use same guid so caller can remove using origFn
        fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
      }

      // 遍历this对象,调用jQueryevent对象的add方法处理事件
      return this.each( function() {
        jQuery.event.add( this, types, fn, data, selector );
      });
    },

    通过分析on方法的源码发现,on方法并没有处理事件相关的任何事情,只是对用户传入的参数进行调整,真正处理事件的是其内部的jQuery.event对象的add方法。

    event对象的构造函数都做了什么工作

    jQuery.Event = function( src, props ) {
      // 余老板的suggest组件中也用到了这种方法

      // 检测this是不是Event对象,如果不是,new一个Event对象出来,这样就避免了外部new对象
      if ( !(this instanceof jQuery.Event) ) {
        return new jQuery.Event( src, props );
      }

      // 如果有src,并且src有type属性
      if ( src && src.type ) {

        // 定义originalEvent属性并将src赋值给它
        this.originalEvent = src;

        // 定义type属性,并将src.type赋值给它
        this.type = src.type;

        // 定义isDefaultPrevented属性并通过判断事件被阻止冒泡为其赋值
        this.isDefaultPrevented = ( src.defaultPrevented ||
          src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse;

      // 否则,将src赋值给type
      } else {
        this.type = src;
      }

      // 如果用户传入props,则扩展Event或者覆盖原有的属性
      if ( props ) {
        jQuery.extend( this, props );
      }

      // 创建一个时间戳
      this.timeStamp = src && src.timeStamp || jQuery.now();

      // 给这个Event对象一个标记
      this[ jQuery.expando ] = true;
    };

    jQuery的event对象封装的方法和属性

     jQuery的event对象提供了如下方法和属性:

        {

          add : function(){},

          remove : function(){},

          trigger : function(){},

          dispatch : function(){},

          handlers : function(){},

          fix: function(){},

          simulate : function(){},

          global : {},

          props : {},

          fixHooks : {},

          keyHooks : {},

          mouseHooks : {},

          special : {}

        }

      首先看add方法:

      add: function( elem, types, handler, data, selector ) {

        var handleObjIn, eventHandle, tmp,
          events, t, handleObj,
          special, handlers, type, namespaces, origType,
          elemData = data_priv.get( elem );

        // 涉及到jQuery的另外一个大的方面:缓存机制。

        // 不为text、comment节点绑定数据,直接返回
        if ( !elemData ) {
          return;
        }

        // 如果handler是一个有handler属性或方法的对象,则进行一些转移赋值操作
        if ( handler.handler ) {
          handleObjIn = handler;
          handler = handleObjIn.handler;
          selector = handleObjIn.selector;
        }

        // 检查handler是否有一个唯一的id,方便之后查找和删除
        if ( !handler.guid ) {

          // 如果没有就为其设定一个唯一id
          handler.guid = jQuery.guid++;
        }

        // 如果elemData中没有events对象,则为其定义events属性并赋值为空对象
        if ( !(events = elemData.events) ) {
          events = elemData.events = {};
        }

        // 如果elemData中没有handle对象
        if ( !(eventHandle = elemData.handle) ) {

          // 为elemData定义一个handle方法(事件处理函数)
          eventHandle = elemData.handle = function( e ) {
            // 有点迷糊。。。
            return typeof jQuery !== core_strundefined && (!e || jQuery.event.triggered !== e.type) ?
              jQuery.event.dispatch.apply( eventHandle.elem, arguments ) :
              undefined;
          };
          // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events
          eventHandle.elem = elem;
        }

        // 处理types中传入的是通过空格分割的多个事件的情况
        types = ( types || "" ).match( core_rnotwhite ) || [""];
          t = types.length;
          while ( t-- ) {
            tmp = rtypenamespace.exec( types[t] ) || [];
            type = origType = tmp[1];
            namespaces = ( tmp[2] || "" ).split( "." ).sort();

            if ( !type ) {
              continue;
          }

          // 事件是否会改变当前状态,如果是则使用特殊事件,看event的special属性。。。
          special = jQuery.event.special[ type ] || {};

          // 根据是否有selector判断使用哪种特殊事件(看完特殊事件再过来看这个地方)
          type = ( selector ? special.delegateType : special.bindType ) || type;

          // 根据新的type获取新的special
          special = jQuery.event.special[ type ] || {};

          // 组装用于特殊事件处理的对象
          handleObj = jQuery.extend({
            type: type,
            origType: origType,
            data: data,
            handler: handler,
            guid: handler.guid,
            selector: selector,
            needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
            namespace: namespaces.join(".")
          }, handleObjIn );

          // 如果是第一次调用,初始化事件处理队列(将同一事件的处理函数放入数组中)
          if ( !(handlers = events[ type ]) ) {
            handlers = events[ type ] = [];
            handlers.delegateCount = 0;

            // 如果获取特殊事件监听方法失败,则使用addEventListener添加事件(抛弃attachEvent了吗?)
            if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
              if ( elem.addEventListener ) {
                elem.addEventListener( type, eventHandle, false );
              }
            }
          }

          // 使用special的add方法进行处理

          if ( special.add ) {

            special.add.call( elem, handleObj );

            if ( !handleObj.handler.guid ) {
              handleObj.handler.guid = handler.guid;
            }
          }

          if ( selector ) {
            handlers.splice( handlers.delegateCount++, 0, handleObj );
          } else {
            handlers.push( handleObj );
          }

          jQuery.event.global[ type ] = true;
        }

        // 清空elem,避免内存泄漏
        elem = null;
      },

    小节

    jQuery推出on()的目的有两个,一是为了统一接口,二是为了提高性能,所以从现在开始用on()替换bind(), live(), delegate吧。尤其是不要再用live()了,因为它已经处于不推荐使用列表了,随时会被干掉。如果只绑定一次事件,那接着用one()吧,这个没有变化。推荐使用on() off().

    注:jQuery1.9删除了一些在1.8中已经过时的api

    jQuery1.9删除了一些在1.8中已经过时的api,想要把那些不够安全的、缺乏效率的、用处不大的,以及带有误导的特性统统去掉。如果你想升级你的jquery版本,但又使用了如下被删除的api的话,可以引入Migrate迁移插件,被删除的api可以在Migrate插件中修复。

    .toggle(function, function, … )
    toggle()方法可实现点击一个元素来执行指定函数。此方法被删除以减少混乱和提高潜在的模块化程度。

    jQuery.browser()
    jQuery.browser()通过UA信息来检测浏览器。此方法在1.3版本中已不赞成使用,并在1.9版本中被删除,jquery团队更建议通过特性检测来时您的代码兼容浏览器。

    .live()
    live()方法可以为未来生成的元素添加事件,此方法在1.7版本中已不赞成使用,并在1.9版本中被删除,您可以使用on()方法来代替。

    .die()
    die()方法可以移除live()添加的事件,此方法在1.7版本中已不赞成使用,并在1.9版本中被删除,您可以使用off()方法来代替。

    .sub()
    sub()方法可以可创建一个新的jQuery副本,不影响原有的jQuery对像,但用例的数量已经不足以证明它存在的价值。

    jQuery下事件处理

    bind() 向元素添加事件处理程序

    blur() 添加/触发 blur 事件

    change() 添加/触发 change 事件

    click() 添加/触发 click 事件

    dblclick() 添加/触发 doubleclick 事件

    delegate() 向匹配元素的当前或未来的子元素添加处理程序

    die() 在版本 1.9 中被移除。移除所有通过 live() 方法添加的事件处理程序

    error() 在版本 1.8 中被废弃。添加/触发 error 事件

    event.currentTarget 在事件冒泡阶段内的当前 DOM 元素

    event.data 包含当前执行的处理程序被绑定时传递到事件方法的可选数据

    event.delegateTarget 返回当前调用的 jQuery 事件处理程序所添加的元素

    event.isDefaultPrevented() 返回指定的 event 对象上是否调用了event.preventDefault()

    event.isImmediatePropagationStopped() 返回指定的 event 对象上是否调用了event.stopImmediatePropagation()

    event.isPropagationStopped() 返回指定的 event 对象上是否调用了event.stopPropagation()

    event.namespace 返回当事件被触发时指定的命名空间

    event.pageX 返回相对于文档左边缘的鼠标位置

    event.pageY 返回相对于文档上边缘的鼠标位置

    event.preventDefault() 阻止事件的默认行为

    event.relatedTarget 返回当鼠标移动时哪个元素进入或退出

    event.result 包含由被指定事件触发的事件处理程序返回的最后一个值

    event.stopImmediatePropagation() 阻止其他事件处理程序被调用

    event.stopPropagation() 阻止事件向上冒泡到 DOM 树,阻止任何父处理程序被事件通知

    event.target 返回哪个 DOM 元素触发事件

    event.timeStamp 返回从 1970 年 1 月 1 日到事件被触发时的毫秒数

    event.type 返回哪种事件类型被触发

    event.which 返回指定事件上哪个键盘键或鼠标按钮被按下

    event.metaKey 事件触发时 META 键是否被按下

    focus() 添加/触发 focus 事件

    focusin() 添加事件处理程序到 focusin 事件

    focusout() 添加事件处理程序到 focusout 事件

    hover() 添加两个事件处理程序到 hover 事件

    keydown() 添加/触发 keydown 事件

    keypress() 添加/触发 keypress 事件

    keyup() 添加/触发 keyup 事件

    live() 在版本 1.9 中被移除。添加一个或多个事件处理程序到当前或未来的被选元素

    load() 在版本 1.8 中被废弃。添加一个事件处理程序到 load 事件

    mousedown() 添加/触发 mousedown 事件

    mouseenter() 添加/触发 mouseenter事件

    mouseleave() 添加/触发 mouseleave事件

    mousemove() 添加/触发 mousemove 事件

    mouseout() 添加/触发 mouseout 事件

    mouseover() 添加/触发 mouseover 事件

    mouseup() 添加/触发 mouseup 事件

    off() 移除通过 on() 方法添加的事件处理程序

    on() 向元素添加事件处理程序

    one() 向被选元素添加一个或多个事件处理程序。该处理程序只能被每个元素触发一次

    $.proxy() 接受一个已有的函数,并返回一个带特定上下文的新的函数

    ready() 规定当 DOM 完全加载时要执行的函数

    resize() 添加/触发 resize 事件

    scroll() 添加/触发 scroll 事件

    select() 添加/触发 select 事件

    submit() 添加/触发 submit 事件

    toggle() 在版本 1.9 中被移除。添加 click 事件之间要切换的两个或多个函数

    trigger() 触发绑定到被选元素的所有事件

    triggerHandler() 触发绑定到被选元素的指定事件上的所有函数

    unbind() 从被选元素上移除添加的事件处理程序

    undelegate() 从现在或未来的被选元素上移除事件处理程序

    unload() 在版本 1.8 中被废弃。添加事件处理程序到 unload 事件

    contextmenu() 添加事件处理程序到 contextmenu事件

    $.holdReady() 用于暂停或恢复.ready() 事件的执行

    HTML对象获取问题

    FireFox:document.getElementById(“idName”);
    ie:document.idname或者document.getElementById(“idName”).
    解决办法:统一使用document.getElementById(“idName”);

    const问题

    说明:Firefox下,可以使用const关键字或var关键字来定义常量;
    IE下,只能使用var关键字来定义常量.
    解决方法:统一使用var关键字来定义常量.

    event.x与event.y问题

    说明:IE下,event对象有x,y属性,但是没有pageX,pageY属性;
    Firefox下,event对象有pageX,pageY属性,但是没有x,y属性.
    解决方法:使用mX(mX = event.x ? event.x : event.pageX;)来代替IE下的event.x或者Firefox下的event.pageX.

    window.location.href问题

    说明:IE或者Firefox2.0.x下,可以使用window.location或window.location.href;
    Firefox1.5.x下,只能使用window.location.
    解决方法:使用window.location来代替window.location.href.

    frame问题

    以下面的frame为例:

    (1)访问frame对象:
    IE:使用window.frameId或者window.frameName来访问这个frame对象. frameId和frameName可以同名。
    Firefox:只能使用window.frameName来访问这个frame对象.
    另外,在IE和Firefox中都可以使用window.document.getElementById(“frameId”)来访问这个frame对象.
    (2)切换frame内容:
    在 IE和Firefox中都可以使用window.document.getElementById(“testFrame”).src = “xxx.html”或window.frameName.location = “xxx.html”来切换frame的内容.
    如果需要将frame中的参数传回父窗口(注意不是opener,而是parent frame),可以在frame中使用parent来访问父窗口。例如:parent.document.form1.filename.value=”Aqing”;

    模态和非模态窗口问题

    说明:IE下,可以通过showModalDialog和showModelessDialog打开模态和非模态窗口;Firefox下则不能.
    解决方法:直接使用window.open(pageURL,name,parameters)方式打开新窗口。
    如果需要将子窗口中的参数传递回父窗口,可以在子窗口中使用window.opener来访问父窗口.
    例如:var parWin = window.opener; parWin.document.getElementById(“Aqing”).value = “Aqing”;

    firefox与IE的父元素(parentElement)的区别

    IE:obj.parentElement
    firefox:obj.parentNode
    解决方法: 因为firefox与IE都支持DOM,因此使用obj.parentNode是不错选择.

    document.formName.item(”itemName”) 问题

    问题说明:IE下,可以使用document.formName.item(”itemName”) 或document.formName.elements [“elementName”];Firefox 下,只能使用document.formName.elements[“elementName”]。
    解决方法:统一使用document.formName.elements[“elementName”]。

    集合类对象问题

    问题说明:IE下,可以使用 () 或 [] 获取集合类对象;Firefox下,只能使用 [ ]获取集合类对象。
    解决方法:统一使用 [] 获取集合类对象。

    自定义属性问题

    问题说明:IE下,可以使用获取常规属性的方法来获取自定义属性,也可以使用getAttribute() 获取自定义属性;Firefox下,只能使用getAttribute() 获取自定义属性。
    解决方法:统一通过getAttribute() 获取自定义属性

    input.type属性问题

    问题说明:IE下input.type属性为只读;但是Firefox下input.type属性为读写。
    解决办法:不修改input.type属性。如果必须要修改,可以先隐藏原来的input,然后在同样的位置再插入一个新的input元素。

    event.srcElement问题

    问题说明:IE下,even对象有srcElement属性,但是没有target属性;Firefox下,even对象有target属性,但是没有srcElement属性。
    解决方法:使用srcObj = event.srcElement ?event.srcElement : event.target;
    如果考虑第8条问题,就改用myEvent代替event即可

    body载入问题

    问题说明:Firefox的body对象在body标签没有被浏览器完全读入之前就存在;而IE的body对象则必须在body标签被浏览器完全读入之后才存在。
    [注] 这个问题尚未实际验证,待验证后再来修改。
    [注] 经验证,IE6、Opera9以及FireFox2中不存在上述问题,单纯的JS脚本可以访问在脚本之前已经载入的所有对象和元素,即使这个元素还没有载入完成。

    事件委托方法

    问题说明:IE下,使用document.body.onload = inject; 其中function inject()在这之前已被实现;在Firefox下,使用document.body.onload = inject();
    解决方法:统一使用document.body.οnlοad=new Function(’inject()’); 或者document.body.onload = function(){/* 这里是代码 */}
    [注意] Function和function的区别

    Table操作问题

    问题说明:ie、firefox以及其它浏览器对于 table 标签的操作都各不相同,在ie中不允许对table和tr的innerHTML赋值,使用js增加一个tr时,使用appendChild方法也不管用。
    解决方法://向table追加一个空行:
    var row = otable.insertRow(-1);var cell = document.createElement(“td”);cell.innerHTML = “”;cell.className = “XXXX”;row.appendChild(cell);[注] 由于俺很少使用JS直接操作表格,这个问题没有遇见过。建议使用JS框架集来操作table,如JQuery

    对象宽高赋值问题

    问题说明:FireFox中类似obj.style.height = imgObj.height的语句无效。

  • 相关阅读:
    java Servlet小结
    Java 自定义客户端与服务器
    JAVA IO流总结
    java udp与tcp
    tomcat作为服务器的配置
    Linux
    Git -- 如何删除本地仓库
    ASP.NET Core 基础 Startup 类
    ASP.NET Core解说之Middleware(中间件)
    一、Redis安装 Redis学习记录
  • 原文地址:https://www.cnblogs.com/ycyc123/p/14030699.html
Copyright © 2020-2023  润新知