首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> ASP.NET 基礎 >> 關於ASP.NET

ASP.NET 封裝 JavaScript 元件化開發:以 ShowModalDialog 為例的伺服器端腳本管理框架

     編輯:關於ASP.NET

在 ASP.NET WebForms 時代,前端 JavaScript 常散落在 `.aspx` 頁面、使用者控制項、甚至後台代碼 `RegisterStartupScript` 中,難以維護與複用。本文展示一個完整的伺服器端腳本元件化框架:定義 `IExecuteScript` 介面、實作 `ShowModalDialog` 類別封裝 `window.showModalDialog` 邏輯、搭配 `RegisterScript` 靜態類別註冊客戶端事件,實現「伺服器端配置、客戶端執行」的關注點分離。

架構設計

IExecuteScript (介面)
  └─ ShowModalDialog : 彈出視窗並接收回傳值
      ├─ 屬性:PageContainer, OpenPage, Height, Width, Parent
      ├─ 集合:Parameters (傳遞參數), ReturnElements (接收回傳值對應控制項)
      └─ Execute() → 產生完整 JavaScript 字串

ReturnElement : 回傳值映射 (控制項 ClientID ↔ Key)
Parameter : 傳遞參數描述 (名稱、值、型別: Element/Select)
RegisterScript : 靜態註冊工具
  ├─ RegiOnClick(Control, IExecuteScript) : 綁定 onclick
  └─ RegiPageClient(Page, key, ReturnValues) : 頁面載入註冊回傳處理

核心類別實作精華 (C#)

public interface IExecuteScript { string Execute(); }

public class ShowModalDialog : IExecuteScript
{
    private const string DialogTemplate = 
        "window.showModalDialog({0}, ' ', 'dialogHeight:{1}px;dialogWidth:{2}px;...');";

    public string PageContainer { get; set; } // 容器頁 URL
    public string OpenPage { get; set; }      // 目標頁 URL
    public int Height { get; set; } = 400;
    public int Width { get; set; } = 400;
    public bool Parent { get; set; }          // 是否使用 parent.

    public ReturnElementCollection ReturnElements { get; } = new ReturnElementCollection();
    public ParameterCollection Parameters { get; } = new ParameterCollection();

    public string Execute()
    {
        string url = $"'{PageContainer}?pageurl=' + {GetPage()}";
        url = string.Format(DialogTemplate, url, Height, Width);
        url = GetParent() + url;

        if (ReturnElements.Count > 0)
        {
            url = "var getvalue=" + url + ";if(getvalue != null){";
            foreach (ReturnElement item in ReturnElements)
                url += item.GetScript(GetParent());
            url += "}";
        }
        return url + ";";
    }

    private string GetPage()
    {
        if (Parameters.Count == 0) return $"'{OpenPage}'";
        var sb = new StringBuilder($"'{OpenPage}'");
        for (int i = 0; i < Parameters.Count; i++)
        {
            var p = Parameters[i];
            string param = p.Element == ElementType.Element
                ? $"'{p.Name}=' + {GetParent()}document.all('{p.Value}').value"
                : $"'{p.Name}=' + {GetParent()}__getSeletedButton({GetParent()}document.all('{p.Value}'))";
            sb.Append(i == 0 ? $" + '{HttpUtility.UrlEncode("?")}' + {param}" 
                             : $" + '{HttpUtility.UrlEncode("&")}' + {param}");
        }
        return sb.ToString();
    }
    // ... GetParent() 等輔助方法
}

使用範例:開啟查詢視窗並回填結果

呼叫端 (父頁面)

var dialog = new ShowModalDialog(
    WebBoot + "Appunit/WindowOpenDialog.aspx", 
    FrmFailureLogSearch.PageURI());
dialog.Height = 400;
dialog.Width = 600;
// 指定回傳值填入哪個控制項
dialog.ReturnElements.Add(new ReturnElement(txtReturn.ClientID, "ReturnString"));
// 註冊到按鈕點擊事件
RegisterScript.RegiOnClick(cmdSearch, dialog);

被呼叫端 (子視窗頁面)

var returnValue = new ReturnValues();
returnValue.Add("ReturnString", filter); // filter 為查詢條件字串
RegisterScript.RegiPageClient(this, "return", returnValue);

框架優勢與擴充性

特性說明
強型別配置編譯期檢查屬性拼寫、型別錯誤
參數化 URL 建構自動處理 QueryString 編碼、多參數串接
回傳值聲明式映射伺服器端指定 `ControlID` ↔ `Key`,客戶端自動填入
支援多種參數來源`Element` (輸入框值)、`Select` (RadioButtonList 選中值)
可擴充新腳本類型實作 `IExecuteScript` 即可:`ConfirmDialog`、`AjaxPost`、`PrintPreview` 等

現代化視角:為什麼不直接寫 JavaScript?

  • WebForms 事件模型 (PostBack) 與客戶端腳本耦合度高
  • 伺服器端控制項 `ClientID` 動態產生 (`ctl00_Content_txtReturn`),硬編碼極易斷
  • 此框架將「什麼時候執行什麼腳本」集中管理,降低認知負荷

遷移至現代架構建議

  1. 改用 **Web API + 前端框架** (Vue/React/Blazor) 徹底分離關注點
  2. 若維護 WebForms,可引入 **TypeScript** 定義介面,編譯期檢查 JS 互動契約
  3. 將 `RegisterScript` 替換為 `ScriptManager.RegisterStartupScript` 標準 API
  4. 棄用 `showModalDialog` (Chrome 37+ 已移除),改用 `window.open` + `postMessage` 或 Modal 元件

此框架是 WebForms 時代「伺服器端主導客戶端行為」的經典產物,雖技術棧已老舊,但其**元件化封裝、聲明式配置、關注點分離**的設計思想,在任何時代的 UI 開發中都值得借鑑。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved