Is there a workaround for IE 6/7 “Unspecified Error” bug when accessing offsetParent

前端 未结 6 1894
一个人的身影
一个人的身影 2020-12-29 15:45

I\'m using jQuery UI\'s draggable and droppable libraries in a simple ASP.NET proof of concept application. This page uses the ASP.NET AJAX UpdatePanel to do partial page up

相关标签:
6条回答
  • 2020-12-29 16:19

    This isn't just a jQuery error. I encountered it using ExtJS 4.0.2a on IE8. It seems that IE will almost always stumble on element.getBoundingClientRect() if the element has been replaced in the DOM. Your try/catch hack is pretty much the only way to get around this. I guess the actual solution would be to eventually drop IE < 9 support.

    Relevent ExtJS v4.0.2a Source Code (lines 11861-11869):

    ...
    if(el != bd){
        hasAbsolute = fly(el).isStyle("position", "absolute");
    
        if (el.getBoundingClientRect) {
            b = el.getBoundingClientRect();
            scroll = fly(document).getScroll();
            ret = [Math.round(b.left + scroll.left), Math.round(b.top + scroll.top)];
        } else {
    ...
    

    With a try/catch fix:

    ...
    if(el != bd){
        hasAbsolute = fly(el).isStyle("position", "absolute");
    
        if (el.getBoundingClientRect) {
            try {
                b = el.getBoundingClientRect();
                scroll = fly(document).getScroll();
                ret = [Math.round(b.left + scroll.left), Math.round(b.top + scroll.top)];
            } catch(e) {
                ret = [0,0];
            }
        } else {
    ...
    
    0 讨论(0)
  • 2020-12-29 16:20

    My version is:

    1. Add function:

      function getOffsetSum(elem) {
          var top = 0, left = 0
          while (elem) {
              top = top + parseInt(elem.offsetTop)
              left = left + parseInt(elem.offsetLeft)
              try {
                  elem = elem.offsetParent
              }
              catch (e) {
                  return { top: top, left: left }
              }
          }
          return { top: top, left: left }
      };
      
    2. replace

      var box  = this[0].getBoundingClientRect()
      

      with

      var box = getOffsetSum(this[0])
      

    PS: jquery-1.3.2.

    0 讨论(0)
  • 2020-12-29 16:25

    i tried the following workaround for the getBoundingClientRect() unspecified error whilst drag n drop, and it works fine.

    in the jquery.1.4.2.js (i.e base jquery file, where the error is thrown exactly)

    replace the elem.getBoundingClientRect() function call in js file

    //the line which throws the unspecified error

    var box = elem.getBoundingClientRect(),

    with this..

    var box = null; try { box = elem.getBoundingClientRect(); } catch(e) { box = { top : elem.offsetTop, left : elem.offsetLeft } ; }

    This solves the issue and drag n drop will work quitely even after post back through update panel

    Regards

    Raghu

    0 讨论(0)
  • 2020-12-29 16:27

    @arilanto - I include this script after my jquery scripts. Performance wise, it's not the best solution, but it is a quick easy work around.

    function IESafeOffsetParent(elem)
    {
        try
        {
           return elem.offsetParent;
        }
        catch(e)
        {        
          return document.body;
        }
    }
    
    // The Offset Method
    // Originally By Brandon Aaron, part of the Dimension Plugin
    // http://jquery.com/plugins/project/dimensions
    jQuery.fn.offset = function() {
    /// <summary>
    ///     Gets the current offset of the first matched element relative to the viewport.
    /// </summary>
    /// <returns type="Object">An object with two Integer properties, 'top' and 'left'.</returns>
    
    var left = 0, top = 0, elem = this[0], results;
    
    if ( elem ) with ( jQuery.browser ) {
        var parent     = elem.parentNode,
            offsetChild  = elem,
            offsetParent = IESafeOffsetParent(elem),
            doc       = elem.ownerDocument,
            safari2   = safari && parseInt(version) < 522 && !/adobeair/i.test(userAgent),
            css       = jQuery.curCSS,
            fixed       = css(elem, "position") == "fixed";
    
        // Use getBoundingClientRect if available
        if (false && elem.getBoundingClientRect) {
            var box = elem.getBoundingClientRect();
    
            // Add the document scroll offsets
            add(box.left + Math.max(doc.documentElement.scrollLeft, doc.body.scrollLeft),
                box.top  + Math.max(doc.documentElement.scrollTop,  doc.body.scrollTop));
    
            // IE adds the HTML element's border, by default it is medium which is 2px
            // IE 6 and 7 quirks mode the border width is overwritable by the following css html { border: 0; }
            // IE 7 standards mode, the border is always 2px
            // This border/offset is typically represented by the clientLeft and clientTop properties
            // However, in IE6 and 7 quirks mode the clientLeft and clientTop properties are not updated when overwriting it via CSS
            // Therefore this method will be off by 2px in IE while in quirksmode
            add( -doc.documentElement.clientLeft, -doc.documentElement.clientTop );
    
        // Otherwise loop through the offsetParents and parentNodes
        } else {
    
            // Initial element offsets
            add( elem.offsetLeft, elem.offsetTop );
    
            // Get parent offsets
            while ( offsetParent ) {
                // Add offsetParent offsets
                add( offsetParent.offsetLeft, offsetParent.offsetTop );
    
                // Mozilla and Safari > 2 does not include the border on offset parents
                // However Mozilla adds the border for table or table cells
                if ( mozilla && !/^t(able|d|h)$/i.test(offsetParent.tagName) || safari && !safari2 )
                    border( offsetParent );
    
                // Add the document scroll offsets if position is fixed on any offsetParent
                if ( !fixed && css(offsetParent, "position") == "fixed" )
                    fixed = true;
    
                // Set offsetChild to previous offsetParent unless it is the body element
                offsetChild  = /^body$/i.test(offsetParent.tagName) ? offsetChild : offsetParent;
                // Get next offsetParent
                offsetParent = offsetParent.offsetParent;
            }
    
            // Get parent scroll offsets
            while ( parent && parent.tagName && !/^body|html$/i.test(parent.tagName) ) {
                // Remove parent scroll UNLESS that parent is inline or a table to work around Opera inline/table scrollLeft/Top bug
                if ( !/^inline|table.*$/i.test(css(parent, "display")) )
                    // Subtract parent scroll offsets
                    add( -parent.scrollLeft, -parent.scrollTop );
    
                // Mozilla does not add the border for a parent that has overflow != visible
                if ( mozilla && css(parent, "overflow") != "visible" )
                    border( parent );
    
                // Get next parent
                parent = parent.parentNode;
            }
    
            // Safari <= 2 doubles body offsets with a fixed position element/offsetParent or absolutely positioned offsetChild
            // Mozilla doubles body offsets with a non-absolutely positioned offsetChild
            if ( (safari2 && (fixed || css(offsetChild, "position") == "absolute")) ||
                (mozilla && css(offsetChild, "position") != "absolute") )
                    add( -doc.body.offsetLeft, -doc.body.offsetTop );
    
            // Add the document scroll offsets if position is fixed
            if ( fixed )
                add(Math.max(doc.documentElement.scrollLeft, doc.body.scrollLeft),
                    Math.max(doc.documentElement.scrollTop,  doc.body.scrollTop));
        }
    
        // Return an object with top and left properties
        results = { top: top, left: left };
    }
    
    function border(elem) {
        /// <summary>
        ///     This method is internal.
        /// </summary>
        /// <private />
        add( jQuery.curCSS(elem, "borderLeftWidth", true), jQuery.curCSS(elem, "borderTopWidth", true) );
    }
    
    function add(l, t) {
        /// <summary>
        ///     This method is internal.
        /// </summary>
        /// <private />
        left += parseInt(l, 10) || 0;
        top += parseInt(t, 10) || 0;
    }
    
    return results;
    };
    
    0 讨论(0)
  • 2020-12-29 16:31

    If you would like to fix the minified/compressed .js file for jQuery version 1.4.2, replace:

    var d=b.getBoundingClientRect(),
    

    with

    var d = null; 
    try { d = b.getBoundingClientRect(); }
    catch(e) { d = { top : b.offsetTop, left : b.offsetLeft } ; }
    

    (note that there is no comma after the closing brace now)

    0 讨论(0)
  • 2020-12-29 16:34

    @Raghu

    Thanks for this bit of code! I was having the same problem in IE and this fixed it.

    var box = null; 
    try { 
        box = elem.getBoundingClientRect(); 
    } catch(e) { 
        box = { 
            top : elem.offsetTop, 
            left : elem.offsetLeft 
        }; 
    }
    
    0 讨论(0)
提交回复
热议问题