Asp.net

訪問 offsetParent 時是否有針對 IE 6/7“未指定錯誤”錯誤的解決方法

  • January 27, 2015

我在一個簡單的 ASP.NET 概念證明應用程序中使用 jQuery UI 的可拖放庫。此頁面使用 ASP.NET AJAX UpdatePanel 進行部分頁面更新。該頁面允許使用者將項目放入垃圾箱 div,這將呼叫從數據庫中刪除記錄的回發,然後重新綁定項目所在的列表(和其他控制項)。所有這些元素(可拖動項和垃圾桶 div)都在 ASP.NET UpdatePanel 中。

這是拖放初始化腳本:

   function initDragging()
   {
       $(".person").draggable({helper:'clone'});
       $("#trashcan").droppable({
           accept: '.person',
           tolerance: 'pointer',
           hoverClass: 'trashcan-hover',
           activeClass: 'trashcan-active',
           drop: onTrashCanned
       });
   }

   $(document).ready(function(){
       initDragging();

       var prm = Sys.WebForms.PageRequestManager.getInstance();
       prm.add_endRequest(function()
       {
           initDragging();
       });
   });

   function onTrashCanned(e,ui)
   {
       var id = $('input[id$=hidID]', ui.draggable).val();
       if (id != undefined)
       {
           $('#hidTrashcanID').val(id);
           __doPostBack('btnTrashcan','');
       }

   }

當頁面回發時,部分更新了 UpdatePanel 的內容,我重新綁定了可拖動對象和可放置對象。然後當我用游標抓取一個可拖動對象時,我得到一個“htmlfile:未指定的錯誤”。例外。我可以通過替換elem.offsetParent我編寫的對這個函式的呼叫來解決 jQuery 庫中的這個問題:

function IESafeOffsetParent(elem)
{
   try
   {
       return elem.offsetParent;
   }
   catch(e)
   {        
       return document.body;
   }
}

我還必須避免呼叫 elem.getBoundingClientRect() ,因為它會引發相同的錯誤。對於那些感興趣的人,我只需要在Dimensions PluginjQuery.fn.offset的函式中進行這些更改。

我的問題是:

  • 雖然這可行,但是否有更好的方法(更清潔;更好的性能;無需修改 jQuery 庫)來解決這個問題?
  • 如果不是,那麼當我將來更新 jQuery 庫時,管理保持我的更改同步的最佳方法是什麼?例如,除了從 jQuery 網站下載的文件中的內聯文件之外,我還可以將庫擴展至其他地方嗎?

更新:

@some 它不可公開訪問,但我會看看 SO 是否會讓我將相關程式碼發佈到這個答案中。只需創建一個 ASP.NET Web 應用程序(將其命名為DragAndDrop)並創建這些文件。不要忘記將 Complex.aspx 設置為您的起始頁。您還需要下載jQuery UI 拖放外掛以及jQuery 核心

複雜的.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Complex.aspx.cs" Inherits="DragAndDrop.Complex" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
   <title>Untitled Page</title>
   <script src="jquery-1.2.6.min.js" type="text/javascript"></script>
   <script src="jquery-ui-personalized-1.5.3.min.js" type="text/javascript"></script>
   <script type="text/javascript">
       function initDragging()
       {
           $(".person").draggable({helper:'clone'});
           $("#trashcan").droppable({
               accept: '.person',
               tolerance: 'pointer',
               hoverClass: 'trashcan-hover',
               activeClass: 'trashcan-active',
               drop: onTrashCanned
           });
       }

       $(document).ready(function(){
           initDragging();

           var prm = Sys.WebForms.PageRequestManager.getInstance();
           prm.add_endRequest(function()
           {
               initDragging();
           });
       });

       function onTrashCanned(e,ui)
       {
           var id = $('input[id$=hidID]', ui.draggable).val();
           if (id != undefined)
           {
               $('#hidTrashcanID').val(id);
               __doPostBack('btnTrashcan','');
           }

       }
   </script>
</head>
<body>
   <form id="form1" runat="server">
   <asp:ScriptManager ID="ScriptManager1" runat="server">
   </asp:ScriptManager>
   <div>
       <asp:UpdatePanel ID="updContent" runat="server" UpdateMode="Always">
   <ContentTemplate>
       <asp:LinkButton ID="btnTrashcan" Text="trashcan" runat="server" CommandName="trashcan" 
           onclick="btnTrashcan_Click" style="display:none;"></asp:LinkButton>
       <input type="hidden" id="hidTrashcanID" runat="server" />
       <asp:Button ID="Button1" runat="server" Text="Save" onclick="Button1_Click" />
       <table>
           <tr>
               <td style="width: 300px;">
                   <asp:DataList ID="lstAllPeople" runat="server" DataSourceID="odsAllPeople"
                       DataKeyField="ID">
                       <ItemTemplate>
                           <div class="person">
                               <asp:HiddenField ID="hidID" runat="server" Value='<%# Eval("ID") %>' />
                               Name:
                               <asp:Label ID="lblName" runat="server" Text='<%# Eval("Name") %>' />
                               <br />
                               <br />
                           </div>
                       </ItemTemplate>
                   </asp:DataList>
                   <asp:ObjectDataSource ID="odsAllPeople" runat="server" SelectMethod="SelectAllPeople" 
                       TypeName="DragAndDrop.Complex+DataAccess" 
                       onselecting="odsAllPeople_Selecting">
                       <SelectParameters>
                           <asp:Parameter Name="filter" Type="Object" />
                       </SelectParameters>
                   </asp:ObjectDataSource>
               </td>
               <td style="width: 300px;vertical-align:top;">
                   <div id="trashcan">
                       drop here to delete
                   </div>
                   <asp:DataList ID="lstPeopleToDelete" runat="server" 
                       DataSourceID="odsPeopleToDelete">
                       <ItemTemplate>
                           ID:
                           <asp:Label ID="IDLabel" runat="server" Text='<%# Eval("ID") %>' />
                           <br />
                           Name:
                           <asp:Label ID="NameLabel" runat="server" Text='<%# Eval("Name") %>' />
                           <br />
                           <br />
                       </ItemTemplate>
                   </asp:DataList>
                   <asp:ObjectDataSource ID="odsPeopleToDelete" runat="server" 
                       onselecting="odsPeopleToDelete_Selecting" SelectMethod="GetDeleteList" 
                       TypeName="DragAndDrop.Complex+DataAccess">
                       <SelectParameters>
                           <asp:Parameter Name="list" Type="Object" />
                       </SelectParameters>
                   </asp:ObjectDataSource>
               </td>
           </tr>
       </table>    
   </ContentTemplate>
   </asp:UpdatePanel>
   </div>
   </form>
</body>
</html>

複雜的.aspx.cs

namespace DragAndDrop
{
   public partial class Complex : System.Web.UI.Page
   {
       protected void Page_Load(object sender, EventArgs e)
       {
       }

       protected List<int> DeleteList
       {
           get
           {
               if (ViewState["dl"] == null)
               {
                   List<int> dl = new List<int>();
                   ViewState["dl"] = dl;

                   return dl;
               }
               else
               {
                   return (List<int>)ViewState["dl"];
               }
           }
       }

       public class DataAccess
       {
           public IEnumerable<Person> SelectAllPeople(IEnumerable<int> filter)
           {
               return Database.SelectAll().Where(p => !filter.Contains(p.ID));
           }

           public IEnumerable<Person> GetDeleteList(IEnumerable<int> list)
           {
               return Database.SelectAll().Where(p => list.Contains(p.ID));
           }
       }

       protected void odsAllPeople_Selecting(object sender, ObjectDataSourceSelectingEventArgs e)
       {
           e.InputParameters["filter"] = this.DeleteList;
       }

       protected void odsPeopleToDelete_Selecting(object sender, ObjectDataSourceSelectingEventArgs e)
       {
           e.InputParameters["list"] = this.DeleteList;
       }

       protected void Button1_Click(object sender, EventArgs e)
       {
           foreach (int id in DeleteList)
           {
               Database.DeletePerson(id);
           }

           DeleteList.Clear();
           lstAllPeople.DataBind();
           lstPeopleToDelete.DataBind();
       }

       protected void btnTrashcan_Click(object sender, EventArgs e)
       {
           int id = int.Parse(hidTrashcanID.Value);
           DeleteList.Add(id);
           lstAllPeople.DataBind();
           lstPeopleToDelete.DataBind();
       }
   }
}

數據庫.cs

namespace DragAndDrop
{
   public static class Database
   {
       private static Dictionary<int, Person> _people = new Dictionary<int,Person>();
       static Database()
       {
           Person[] people = new Person[]
           {
               new Person("Chad")
               , new Person("Carrie")
               , new Person("Richard")
               , new Person("Ron")
           };
           foreach (Person p in people)
           {
               _people.Add(p.ID, p);
           }
       }

       public static IEnumerable<Person> SelectAll()
       {
           return _people.Values;
       }

       public static void DeletePerson(int id)
       {
           if (_people.ContainsKey(id))
           {
               _people.Remove(id);
           }
       }

       public static Person CreatePerson(string name)
       {
           Person p = new Person(name);
           _people.Add(p.ID, p);

           return p;
       }
   }

   public class Person
   {
       private static int _curID = 1;
       public int ID { get; set; }
       public string Name { get; set; }
       public Person()
       {
           ID = _curID++;
       }

       public Person(string name)
           : this()
       {
           Name = name;
       }
   }
}

@arilanto - 我在我的 jquery 腳本之後包含了這個腳本。性能方面,它不是最好的解決方案,但它是一個快速簡單的解決方法。

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;
};

引用自:https://stackoverflow.com/questions/371468