開發 ASP.NET 伺服器控件時,需將 JavaScript 註冊至頁面,確保不重複、正確載入順序、支援部分回發。本文介紹標準做法:OnPreRender 階段配合 ClientScriptManager 註冊腳本塊與腳本引用。
核心模式
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
RegisterScripts();
}
private void RegisterScripts()
{
// 1. 註冊內嵌腳本塊(僅一次)
const string scriptKey = "MyControl_InlineScript";
if (!Page.ClientScript.IsClientScriptBlockRegistered(GetType(), scriptKey))
{
string script = @"
function validateNumber(input) {
// 驗證邏輯
return true;
}
";
Page.ClientScript.RegisterClientScriptBlock(GetType(), scriptKey, script, true); // true = 自動加 script 標籤
}
// 2. 註冊外部 .js 檔案引用
const string includeKey = "MyControl_ExternalJs";
if (!Page.ClientScript.IsClientScriptIncludeRegistered(includeKey))
{
Page.ClientScript.RegisterClientScriptInclude(includeKey, ResolveClientUrl("~/Scripts/MyControl.js"));
}
}
在渲染屬性時綁定事件
protected override void AddAttributesToRender(HtmlTextWriter writer)
{
base.AddAttributesToRender(writer);
// 呼叫已註冊的 JS 函數
writer.AddAttribute("onkeypress", "return validateNumber(this);");
}
關鍵點解析
| 方法 | 用途 | 去重鍵 |
| RegisterClientScriptBlock | 內嵌腳本內容 | Type + Key |
| RegisterClientScriptInclude | 外部 .js 引用 | Key |
| RegisterStartupScript | 頁面載入後執行 | Type + Key |
| RegisterOnSubmitStatement | 表單提交前執行 | Type + Key |
常見坑與解決
- UpdatePanel 部分回發:
ClientScriptManager 不會重新註冊。改用 ScriptManager.RegisterClientScriptBlock/Include,需判斷 ScriptManager.GetCurrent(Page)?.IsInAsyncPostBack。
- 腳本相依順序:先註冊 jQuery 等依賴庫,再註冊自定義腳本。可用
ScriptManager.ScriptResourceMapping 定義相依。
- GUID 做 Key:避免多控件實例 Key 衝突,建議
Guid.NewGuid().ToString("N") 或 GetType().FullName + "_Script"。
- ResolveClientUrl:確保外部 .js 路徑在 Master Page、用戶控件、巢狀目錄下正確解析。
完整控件範例
[ToolboxData("<{0}:NumericTextBox runat=server></{0}:NumericTextBox>")]
public class NumericTextBox : TextBox
{
private const string ScriptKey = "NumericTextBox_ValidationScript";
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
RegisterValidationScript();
}
private void RegisterValidationScript()
{
if (!Page.ClientScript.IsClientScriptBlockRegistered(GetType(), ScriptKey))
{
string script = @"
function NumericTextBox_Validate(ctrl) {
var key = window.event ? event.keyCode : ctrl.which;
// 允許數字、Backspace、Tab、小數點、負號
return (key >= 48 && key <= 57) || key == 8 || key == 9 || key == 46 || key == 45;
}
";
Page.ClientScript.RegisterClientScriptBlock(GetType(), ScriptKey, script, true);
}
}
protected override void AddAttributesToRender(HtmlTextWriter writer)
{
base.AddAttributesToRender(writer);
writer.AddAttribute("onkeypress", "return NumericTextBox_Validate(this);");
}
}
總結
- 在
OnPreRender 註冊腳本,確保控件樹建立完成。
- 使用
IsClientScriptBlockRegistered/IsClientScriptIncludeRegistered 防重複。
- 內嵌腳本用
RegisterClientScriptBlock,外部檔用 RegisterClientScriptInclude。
- 在
AddAttributesToRender 綁定事件屬性。
- 含 UpdatePanel 專案改用
ScriptManager 同名方法。
遵循此模式,自定義控件的 JavaScript 管理將健壯、可維護、無衝突。
- 上一篇文章: ASP.NET 頁面指令中 CodeBehind 與 Src 的區別及找不到 CS 文件的解決
- 下一篇文章: ASP.NET 中 jQuery 動態操作 DropDownList 級聯與後台獲取值
Copyright ©
程式碼之家 All Rights Reserved