Asp.net
訪問 offsetParent 時是否有針對 IE 6/7“未指定錯誤”錯誤的解決方法
我在一個簡單的 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 Plugin
jQuery.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; };