WebForms中如何让Ajax modal pop up extender弹窗跟随触发按钮定位
Ajax ModalPopupExtender 跟随触发按钮定位实现方案
ModalPopupExtender默认固定居中的表现是控件内置的重定位逻辑导致的,不需要换控件,按以下步骤修改即可实现弹窗始终显示在GridView行触发按钮的相邻位置,完全适配VS2015 WebForms + Ajax Control Toolkit的开发环境。
第一步:修改ModalPopupExtender基础配置,关闭默认强制居中逻辑
给弹窗对应的ModalPopupExtender控件添加两个属性,禁用内置的自动重定位:RepositionMode="None"
如果你需要保留弹窗的拖拽功能,同时设置PopupDragHandleControlID为弹窗的标题栏容器ID即可,后续拖拽操作不会被强制重置位置。
注意不要直接把GridView内的行按钮设为TargetControlID——因为行按钮是GridView动态渲染的,你可以把TargetControlID绑定到页面上一个隐藏的静态按钮(加style="display:none"即可),所有行按钮的触发逻辑统一走JS控制。同时给ModalPopupExtender设置BehaviorID="mpeAddRow",方便JS获取控件实例。第二步:编写客户端JS逻辑,弹窗显示前动态计算位置
不需要引入额外第三方库,直接写原生JS即可,逻辑是点击行按钮时先记录触发按钮的引用,手动调用弹窗显示方法,等弹窗渲染完成后根据按钮的视口坐标计算弹窗位置,同时做边界判断避免弹窗超出屏幕被截断:
// 存储当前触发弹窗的行按钮引用 var activeTriggerBtn = null; // 行按钮点击入口方法 function triggerAddRowPopup(btn, e) { // 阻止按钮默认的回发行为 e.preventDefault(); activeTriggerBtn = btn; // 获取ModalPopupExtender的客户端实例 var popupInstance = $find("mpeAddRow"); // 绑定弹窗显示完成后的回调,执行位置调整 popupInstance.add_shown(setPopupPosition); popupInstance.show(); } // 动态计算并设置弹窗位置 function setPopupPosition() { if (!activeTriggerBtn) return; // 替换成你自己的弹窗Panel的客户端ID var popupDom = document.getElementById("<%= pnlAddControl.ClientID %>"); // 获取触发按钮的视口位置矩形 var btnRect = activeTriggerBtn.getBoundingClientRect(); // 默认位置:按钮右侧偏移10px,垂直方向和按钮居中对齐 var posLeft = btnRect.right + 10; var posTop = btnRect.top + window.scrollY - (popupDom.offsetHeight / 2) + (activeTriggerBtn.offsetHeight / 2); // 边界适配:右侧空间不足则放到按钮左侧 if (posLeft + popupDom.offsetWidth > window.innerWidth + window.scrollX) { posLeft = btnRect.left - popupDom.offsetWidth - 10; } // 边界适配:上方空间不足则放到按钮下方 if (posTop < window.scrollY) { posTop = btnRect.bottom + window.scrollY + 10; } // 边界适配:下方空间不足则放到按钮上方 if (posTop + popupDom.offsetHeight > window.scrollY + window.innerHeight) { posTop = btnRect.top + window.scrollY - popupDom.offsetHeight - 10; } // 覆盖弹窗默认定位样式 popupDom.style.position = "absolute"; popupDom.style.left = posLeft + "px"; popupDom.style.top = posTop + "px"; }
- 第三步:给GridView行内的触发按钮绑定客户端点击事件
在GridView的RowDataBound事件里,给每行的新增按钮绑定上面写的JS方法即可,C#后台代码参考:
protected void gvDataList_RowDataBound(object sender, GridViewRowEventArgs e) { if (e.Row.RowType == DataControlRowType.DataRow) { Button addRowBtn = (Button)e.Row.FindControl("btnAddNewRow"); addRowBtn.Attributes.Add("onclick", "triggerAddRowPopup(this, event);"); } }
补充说明
- 上述JS用到的
getBoundingClientRectAPI兼容IE11及所有现代浏览器,不需要额外引入jQuery,适配VS2015默认的浏览器兼容要求。 - 弹窗原有的全屏遮罩层逻辑不需要修改,不会影响定位效果;如果不需要遮罩,直接把ModalPopupExtender的
BackgroundCssClass属性置空即可。 - 如果需要弹窗在页面滚动、窗口大小变化时始终跟随触发按钮,只要给window的
scroll、resize事件绑定setPopupPosition方法即可。
内容的提问来源于stack exchange,提问作者altaaf.hussein
相关产品推荐
相关产品推荐

