ASP.NET - 使用 Microsoft AJAX Library 創建自定義客戶端腳本

當您要執行下列操作時,可以使用 Microsoft AJAX Library 的功能:

·向 JavaScript 代碼中添加面向對象的功能,以提高代碼的重用性、靈活性和可維護性。

·使用反射在運行時檢查客戶端腳本的結構和組件。

·使用枚舉提供不同於整數的另一種易讀的表示形式。

·使用 JavaScript 基類型的擴展縮短常規腳本任務的開發時間。

·使用調試擴展和跟蹤功能,實現比傳統 JavaScript 調試技術更快、信息更豐富的調試。

 

一、使用類型系統

Microsoft AJAX Library 增加了一個類型系統以及一系列對 JavaScript 對象的擴展,可提供與 .NET Framework 功能類似的面向對象的常用功能。利用這些功能,可按一種結構化方式編寫支持 AJAX ASP.NET 應用程序,這不僅能提高可維護性,還簡化了添加功能以及對功能分層的操作。Microsoft AJAX Library 擴展爲 JavaScript 添加了下列功能:

類、命名空間、繼承、接口、枚舉、反射

 

該庫還提供了針對字符串和數組的 Helper 函數。

 

1.1、類、成員和命名空間

Microsoft AJAX Library 包括基類及其派生的對象和組件。通過所有這些類,您可以使用面向對象的編程模型來編寫客戶端腳本。

Type 類爲 JavaScript 編程添加了命名空間、類和繼承等面向對象的功能。任何使用 Type 類註冊的 JavaScript 對象都會自動獲得訪問此功能的權限。下面的示例演示如何使用 Type 類在 JavaScript 文件中創建並註冊一個命名空間和類:

Type.registerNamespace("Demo");

 

Demo.Person = function(firstName, lastName, emailAddress) {

    this._firstName = firstName;

    this._lastName = lastName;

    this._emailAddress = emailAddress;

}

 

Demo.Person.prototype = {

 

    getFirstName: function() {

        return this._firstName;

    },

 

    getLastName: function() {

        return this._lastName;

    },

 

    getName: function() {

        return this._firstName + ' ' + this._lastName;

    },

 

    dispose: function() {

        alert('bye ' + this.getName());

    }

}

Demo.Person.registerClass('Demo.Person', null, Sys.IDisposable);

 

// Notify ScriptManager that this is the end of the script.

if (typeof(Sys) !== 'undefined') Sys.Application.notifyScriptLoaded();

      類有四種成員:字段、屬性、方法和事件。字段和屬性是名稱/值對,用於描述類實例的特徵。字段由基元類型組成,可直接進行訪問,如下面的示例所示:

myClassInstance.name="Fred"

      屬性可以表示任何基元類型或引用類型。屬性值需通過 get set 訪問器方法進行訪問。在 Microsoft AJAX Library 中,get set 訪問器都是函數。按照約定,這些函數的名稱中應使用前綴“get_”或“set_”。例如,若要獲取或設置屬性 cancel 的值,需要調用 get_cancel set_cancel 方法。

對於在 AJAX 客戶端應用程序生命週期中發生的操作,Microsoft AJAX Library 將引發相應的事件進行響應。Microsoft AJAX Library 還提供一種爲 AJAX 客戶端組件創建自定義事件的標準方式。

Microsoft AJAX Library 提供一種有助於對常用功能進行分組的命名空間註冊方式。下面的示例演示如何使用 Type.registerNamespace .registerClass 方法向 Demo 命名空間中添加 Person 類。

若要對 ASP.NET 網頁啓用 AJAX 功能,必須向該頁面添加 ScriptManager 控件。呈現該頁面時,將自動生成對 AJAX 客戶端腳本庫的相應腳本引用。下面的示例演示一個包含 ScriptManager 控件的頁面。

<asp:ScriptManager runat="server" ID="scriptManager" />

      下面的示例演示如何完成以下過程:註冊命名空間,創建類,然後重新註冊該類。

Type.registerNamespace("Demo");

 

Demo.Person = function(firstName, lastName, emailAddress) {

    this._firstName = firstName;

    this._lastName = lastName;

    this._emailAddress = emailAddress;

}

 

Demo.Person.prototype = {

 

    getFirstName: function() {

        return this._firstName;

    },

 

    getLastName: function() {

        return this._lastName;

    },

 

    getName: function() {

        return this._firstName + ' ' + this._lastName;

    },

 

    dispose: function() {

        alert('bye ' + this.getName());

    }

}

Demo.Person.registerClass('Demo.Person', null, Sys.IDisposable);

 

// Notify ScriptManager that this is the end of the script.

if (typeof(Sys) !== 'undefined') Sys.Application.notifyScriptLoaded();

 

Type.registerNamespace("Demo");

 

Demo.Person = function(firstName, lastName, emailAddress) {

    this._firstName = firstName;

    this._lastName = lastName;

    this._emailAddress = emailAddress;

}

 

Demo.Person.prototype = {

 

    getFirstName: function() {

        return this._firstName;

    },

 

    getLastName: function() {

        return this._lastName;

    },

 

    getName: function() {

        return this._firstName + ' ' + this._lastName;

    },

 

    dispose: function() {

        alert('bye ' + this.getName());

    }

}

Demo.Person.registerClass('Demo.Person', null, Sys.IDisposable);

 

// Notify ScriptManager that this is the end of the script.

if (typeof(Sys) !== 'undefined') Sys.Application.notifyScriptLoaded();

 

1.2、訪問修飾符

大多數面向對象的編程語言都包括“訪問修飾符”這一概念。通過訪問修飾符,可以指定類或成員可用的上下文,例如是對外部程序可用,還是對同一命名空間中的內部類可用,抑或是僅在特定的代碼塊中可用。JavaScript 中沒有訪問修飾符。但是,Microsoft AJAX Library 遵循以下約定:名稱以下劃線字符(“_”)開頭的成員視爲私有成員,不能從成員所屬類的外部訪問它們。

 

1.3、繼承

繼承是指一個類從另一個類派生的能力。派生類可自動繼承基類的所有字段、屬性、方法和事件。派生類可以添加新成員或者重寫基類的現有成員,以更改這些成員的行爲。

下面的示例包含兩個在腳本中定義的類:Person Employee,其中 Employee 派生自 Person。這兩個類演示私有字段的用法,並且它們都具有公共屬性和方法。此外,Employee 還重寫 Person 類的 toString 實現並使用基類的功能。

Type.registerNamespace("Demo");

 

Demo.Person = function(firstName, lastName, emailAddress) {

    this._firstName = firstName;

    this._lastName = lastName;

    this._emailAddress = emailAddress;

}

 

Demo.Person.prototype = {

    getFirstName: function() {

        return this._firstName;

    },

 

    getLastName: function() {

        return this._lastName;

    },

 

    getEmailAddress: function() {

        return this._emailAddress;

    },

    setEmailAddress: function(emailAddress) {

        this._emailAddress = emailAddress;

    },

 

    getName: function() {

        return this._firstName + ' ' + this._lastName;

    },

 

    dispose: function() {

        alert('bye ' + this.getName());

    },

 

    sendMail: function() {

        var emailAddress = this.getEmailAddress();

 

        if (emailAddress.indexOf('@') < 0) {

            emailAddress = emailAddress + '@example.com';

        }

        alert('Sending mail to ' + emailAddress + ' ...');

    },

 

    toString: function() {

        return this.getName() + ' (' + this.getEmailAddress() + ')';

    }

}

 

Demo.Person.registerClass('Demo.Person', null, Sys.IDisposable);

Demo.Employee = function(firstName, lastName, emailAddress, team, title) {

    Demo.Employee.initializeBase(this, [firstName, lastName, emailAddress]);

 

    this._team = team;

    this._title = title;

}

 

Demo.Employee.prototype = {

 

    getTeam: function() {

        return this._team;

    },

    setTeam: function(team) {

        this._team = team;

    },

 

    getTitle: function() {

        return this._title;

    },

    setTitle: function(title) {

        this._title = title;

    },

    toString: function() {

        return Demo.Employee.callBaseMethod(this, 'toString') + '/r/n' + this.getTitle() + '/r/n' + this.getTeam();

    }

}

Demo.Employee.registerClass('Demo.Employee', Demo.Person);

 

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

<html >

<head>

    <title>Inheritance</title>

</head>

 

<body>

    <form id="Main" runat="server">

        <asp:ScriptManager runat="server" ID="scriptManager" />

    <script type="text/javascript" src="Inheritance.js"></script>

    </form>

 

    <h2>Inheritance</h2>

    <p />

 

    <div>

        This file contains two classes defined in script: Person and Employee, where

        Employee derives from Person.

        <p />

 

        Each class has private fields, and public properties and methods. In addition,

        Employee overrides the toString implementation, and in doing so, it uses the

        base class functionality.

        <p />

 

        This example puts the Person class in the "Demo" namespace.

        <p />

    </div>

 

 

    <div>

        <ul>

            <li><a href="#" οnclick="return OnTestNewClick()">Object Creation</a></li>

            <li><a href="#" οnclick="return OnTestDisposeClick()">Object Dispose</a></li>

            <li><a href="#" οnclick="return OnTestPrivatePropertyClick()">Public vs. Private Properties</a></li>

            <li><a href="#" οnclick="return OnTestInstanceMethodClick()">Instance Methods</a></li>

            <li><a href="#" οnclick="return OnTestOverrideMethodClick()">Overriden Methods</a></li>

            <li><a href="#" οnclick="return OnTestInstanceOfClick()">Instance Of Check</a></li>

        </ul>

    </div>

 

    <script type="text/javascript" language="JavaScript">

 

    function GetTestPerson()

    {

        return new Demo.Person('Jane', 'Doe', '[email protected]');

    }

 

    function GetTestEmployee()

    {

        return new Demo.Employee('John', 'Doe', '[email protected]', 'Platform', 'Programmer');

    }

 

    function OnTestNewClick() {

        var aPerson = GetTestPerson();

 

        alert(aPerson.getFirstName());

        alert(aPerson);

        alert(Object.getType(aPerson).getName());

 

        var testPerson = GetTestPerson();

        alert(testPerson.getFirstName());

        alert(testPerson);

 

        return false;

    }

 

    function OnTestDisposeClick() {

        var aPerson = GetTestEmployee();

        alert(aPerson.getFirstName());

        aPerson.dispose();

    }

 

    function OnTestPrivatePropertyClick() {

        var aPerson = GetTestEmployee();

        alert('aPerson._firstName = ' + aPerson._firstName);

        alert('aPersona.getFirstName() = ' + aPerson.getFirstName());

 

        return false;

    }

 

    function OnTestInstanceMethodClick() {

        var aPerson = GetTestEmployee();

        aPerson.sendMail('Hello', 'This is a test mail.');

 

        return false;

    }

 

    function OnTestOverrideMethodClick() {

        var testPerson = GetTestEmployee();

        alert(testPerson);

 

        return false;

    }

 

    function OnTestInstanceOfClick() {

        var aPerson = GetTestEmployee();

        if (Demo.Employee.isInstanceOfType(aPerson)) {

            alert(aPerson.getName() + ' is an Employee instance./r/nTitle property: ' + aPerson.getTitle());

        }

 

        return false;

    }

 

    </script>

</body>

</html>

 

1.4、接口

接口用於定義實現它的類的輸入和輸出要求。這樣,函數可以和實現同一接口的類進行交互,而不用考慮該類還實現哪些其他功能。

下面的示例定義一個 Tree 基類和一個 IFruitTree 接口。兩個派生類 Apple Banana 可實現 IFruitTree 接口,但 Pine 類不實現該接口。實現 IFruitTree 接口的任何類都可確保 bearFruit 方法是該類的成員。

Type.registerNamespace("Demo.Trees");

 

Demo.Trees.IFruitTree = function() {}

Demo.Trees.IFruitTree.Prototype = {

    bearFruit: function(){}

}

Demo.Trees.IFruitTree.registerInterface('Demo.Trees.IFruitTree');

 

 

Demo.Trees.Tree = function(name) {

    this._name = name;

}

Demo.Trees.Tree.prototype = {

    returnName: function() {

        return this._name;

    },

 

    toStringCustom: function() {

        return this.returnName();

    },

 

    makeLeaves: function() {}

}

Demo.Trees.Tree.registerClass('Demo.Trees.Tree');

 

 

Demo.Trees.FruitTree = function(name, description) {

    Demo.Trees.FruitTree.initializeBase(this, [name]);

    this._description = description;

}

Demo.Trees.FruitTree.prototype.bearFruit = function() {

        return this._description;

}

Demo.Trees.FruitTree.registerClass('Demo.Trees.FruitTree', Demo.Trees.Tree, Demo.Trees.IFruitTree);

 

Demo.Trees.Apple = function() {

    Demo.Trees.Apple.initializeBase(this, ['Apple', 'red and crunchy']);

}

Demo.Trees.Apple.prototype = {

    makeLeaves: function() {

        alert('Medium-sized and desiduous');

    },

    toStringCustom: function() {

        return 'FruitTree ' + Demo.Trees.Apple.callBaseMethod(this, 'toStringCustom');

    }

}

Demo.Trees.Apple.registerClass('Demo.Trees.Apple', Demo.Trees.FruitTree);

 

Demo.Trees.GreenApple = function() {

    Demo.Trees.GreenApple.initializeBase(this);

    // You must set the _description feild after initializeBase

    // or you will get the base value.

    this._description = 'green and sour';

}

Demo.Trees.GreenApple.prototype.toStringCustom = function() {

    return Demo.Trees.GreenApple.callBaseMethod(this, 'toStringCustom') + ' ... its GreenApple!';

}

Demo.Trees.GreenApple.registerClass('Demo.Trees.GreenApple', Demo.Trees.Apple);

 

 

Demo.Trees.Banana = function(description) {

    Demo.Trees.Banana.initializeBase(this, ['Banana', 'yellow and squishy']);

}

Demo.Trees.Banana.prototype.makeLeaves = function() {

    alert('Big and green');

}

Demo.Trees.Banana.registerClass('Demo.Trees.Banana', Demo.Trees.FruitTree);

 

 

 

Demo.Trees.Pine = function() {

    Demo.Trees.Pine.initializeBase(this, ['Pine']);

}

Demo.Trees.Pine.prototype.makeLeaves = function() {

    alert('Needles in clusters');

}

Demo.Trees.Pine.registerClass('Demo.Trees.Pine', Demo.Trees.Tree);

 

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

<html >

<head>

    <title>Interface</title>

</head>

 

<body>

    <form id="Main" runat="server">

        <asp:ScriptManager runat="server" ID="scriptManager" />

    </form>

 

    <h2>Interface</h2>

    <p />

 

    <div>

        This file contains a Tree base class, and an IFruitTree interface.

        Apple and Banana, two derived classes implement that interface, whereas,

        Pine does not implement that interface.

        <p />

    </div>

 

    <script type="text/javascript" src="Interface.js"></script>

 

    <div>

        <ul>

                <li><a href="#" οnclick="return OnTestNewClick()">Object Creation</a></li>

                <li><a href="#" οnclick="return OnTestImplementsClick()">Implements Check</a></li>

                <li><a href="#" οnclick="return OnTestInterfaceMethodClick()">Call interface method</a></li>

        </ul>

    </div>

 

    <script type="text/javascript" language="JavaScript">

 

    function OnTestNewClick() {

        var apple = new Demo.Trees.Apple('Apple');

        alert(apple.returnName());

        apple.makeLeaves();

 

        return false;

    }

 

    function OnTestImplementsClick() {

        var apple = new Demo.Trees.Apple();

        if (Demo.Trees.IFruitTree.isImplementedBy(apple)) {

            alert('Apple implements IFruitTree');

        }

        else {

            alert('Apple does not implement IFruitTree');

        }

 

        var pine = new Demo.Trees.Pine();

        if (Demo.Trees.IFruitTree.isImplementedBy(pine)) {

            alert('Pine implements IFruitTree');

        }

        else {

            alert('Pine does not implement IFruitTree');

        }

 

        return false;

    }

 

    function OnTestInterfaceMethodClick() {

        var apple = new Demo.Trees.Apple();

        ProcessTree(apple);

 

        var pine = new Demo.Trees.Pine();

        ProcessTree(pine);

 

        var banana = new Demo.Trees.Banana();

        ProcessTree(banana);

 

        var g = new Demo.Trees.GreenApple();

        ProcessTree(g);

 

        return false;

    }

 

    function ProcessTree(tree) {

        alert('Current Tree ' + tree.returnName());

        alert(tree.toStringCustom());

        if (Demo.Trees.IFruitTree.isImplementedBy(tree)) {

            alert(tree.returnName() + ' implements IFruitTree; Fruit is ' + tree.bearFruit());

        }

    }

    </script>

</body>

</html>

 

1.5、枚舉

枚舉是指包含一組命名整數常量的類。您可以像訪問屬性那樣訪問這些值,如下面的示例所示:

myObject.color = myColorEnum.red

枚舉提供不同於整數的另一種易讀的表示形式。有關 Microsoft AJAX Library 中的枚舉的更多信息,請參見 Type.registerEnum 方法 (ASP.NET AJAX)

下面的示例定義一個命名顏色的枚舉,這些命名顏色用於表示十六進制的值。

Type.registerNamespace("Demo");

 

// Define an enumeration type and register it.

Demo.Color = function(){};

Demo.Color.prototype =

{

    Red:    0xFF0000,

    Blue:   0x0000FF,

    Green:  0x00FF00,

    White:  0xFFFFFF

}

Demo.Color.registerEnum("Demo.Color");

 

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"

    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html >

<head>

    <title>Enumeration</title>

</head>

 

<body>

    <form id="Main" runat="server">

        <asp:ScriptManager runat="server" ID="scriptManager" />

    </form>

 

    <div>

        <p>This example creates an Enumeration of colors

            and applies them to page background.</p>

 

        <select id="ColorPicker"

            οnchange="ChangeColor(options[selectedIndex].value)">

            <option value="Red" label="Red" />

            <option value="Blue" label="Blue" />

            <option value="Green" label="Green" />

            <option value="White" label="White" />

        </select>

 

    </div>

 

    <script type="text/javascript" src="Enumeration.js"></script>

    <script type="text/javascript" language="JavaScript">

 

    function ChangeColor(value)

    {

         document.body.bgColor = eval("Demo.Color." + value + ";");

    }

 

    </script>

 

</body>

</html>

 

1.6、反射

反射是指在運行時檢查程序的結構和組件的能力。實現反射的 API 是對 Type 類的擴展。通過這些方法,可以收集有關對象的信息,例如該對象繼承自誰,它是否實現特定的接口,以及它是否是特定類的實例等。

下面的示例使用反射 API 對前面接口示例中的 GreenApple 類進行測試。

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

<html >

<head>

    <title>Reflection</title>

</head>

 

<body>

    <form id="Main" runat="server">

        <asp:ScriptManager runat="server" ID="scriptManager" />

    </form>

 

    <div>

        <p>This example tests the Demo.Trees.GreenApple class

            against various reflection APIs.</p>

 

        <input id="Button1" value="Check Type"

            type="button" οnclick="return OnButton1Click()" />

        <input id="Button2" value="Check Inheritance"

            type="button" οnclick="return OnButton2Click()" />

        <input id="Button3" value="Check Interface"

            type="button" οnclick="return OnButton3Click()" />

 

    </div>

 

    <script type="text/javascript" src="Interface.js"></script>

    <script type="text/javascript" language="JavaScript">

 

    var g = new Demo.Trees.GreenApple();

    var gt = Demo.Trees.GreenApple;

    var a = new Array(

        Demo.Trees.Apple,

        Demo.Trees.Tree,

        Demo.Trees.Pine,

        Demo.Trees.IFruitTree,

        Sys.IContainer);

 

    function OnButton1Click()

    {

        for (var i = 0; i < a.length; i ++)

        {

            if (a[i].isInstanceOfType(g))

            {

                alert(gt.getName() + " is a " + a[i].getName() + ".");

            }

            else alert(gt.getName() + " is not a " + a[i].getName() + ".");

        }

    }

 

    function OnButton2Click()

    {

        for (var i = 0; i < a.length; i ++)

        {

            if (gt.inheritsFrom(a[i]))

            {

                alert(gt.getName() + " inherits from " + a[i].getName() + ".");

            }

            else alert(gt.getName() + " does not inherit from " + a[i].getName() + ".");

        }

    }

 

    function OnButton3Click()

    {

        for (var i = 0; i < a.length; i ++)

        {

            if (Type.isInterface(a[i]))

            {

                if (gt.implementsInterface(a[i]))

                {

                    alert(gt.getName() + " implements the " + a[i].getName() + " interface.");

                }

                else alert(gt.getName() + " does not implement the " + a[i].getName() + " interface.");

            }

            else alert(a[i].getName() + " is not an interface.");

        }

    }

    </script>

</body>

</html>

 

二、使用 JavaScript 基類型的擴展

JavaScript 基類型的擴展可爲這些類型提供附加功能。

·Array 類型擴展

·Boolean 類型擴展

·Date 類型擴展

·Error 類型擴展

·Number 類型擴展

·Object 類型擴展

·String 類型擴展

Sys.Debug 類可提供豐富的調試功能。

如果基於 Microsoft AJAX Library 創建組件,則可以創建由 ScriptManager 控件自動管理的腳本文件的調試版本和發行版本。通過在腳本文件名中添加“.debug”部分,可以標識腳本文件的調試版本。例如,下面的腳本文件名標識同一文件的零售版本和調試版本:

·MyScript.js(零售版)

·MyScript.debug.js(調試版)

 

三、將客戶端腳本集成到 ASP.NET Web 應用程序中

任何 ASP.NET 網頁均可以通過在 <script> 塊中引用腳本文件來對其進行訪問,如下面的示例所示:

<script type="text/javascript" src="MyScript.js"></script>

但是,以此方式調用的腳本將不能參與部分頁呈現,或無法訪問 Microsoft AJAX Library 的某些組件。若要使腳本文件可在支持 AJAX ASP.NET Web 應用程序中用於部分頁呈現,必須在該頁面的 ScriptManager 控件中註冊該腳本。若要註冊腳本文件,請創建一個指向相關文件的 ScriptReference 對象,並使之將該文件添加到 Scripts 集合中。下面的示例演示如何在標記中執行此操作:

<asp:ScriptManager ID="SMgr" runat="server">

  <Scripts>

    <asp:ScriptReference path="MyScript.js" />

  </Scripts>

</asp:ScriptManager>

      若要使腳本文件得到 ScriptManager 控件的正確處理,每個文件都必須在末尾包含對 Sys.Application.notifyScriptLoaded 方法的調用。此調用可通知應用程序,已完成文件加載。下面的示例演示用於實現此目的的代碼:

if (typeof(Sys) !== 'undefined') Sys.Application.notifyScriptLoaded();

      此外,您還可以將 .js 文件作爲資源嵌入在託管代碼程序集中(如果創建的 ASP.NET 服務器控件在客戶端腳本中實現其 AJAX 功能,則可能需要這樣做)。將腳本嵌入在程序集中時,腳本中便無需包括通知語句。此外,您也不必在腳本引用中指定 path 屬性。但是,必須提供不帶文件擴展名的程序集名稱,如下面的示例所示:

<asp:ScriptManager ID="SMgr" runat="server">

  <Scripts>

    <asp:ScriptReference

        Name="MyScript.js" Assembly="MyScriptAssembly"/>

  </Scripts>

</asp:ScriptManager>

      此外,通過在代碼中創建腳本引用並將它們添加到 Scripts 集合中,還可以用編程方式註冊腳本。有關更多信息,請參見 動態分配腳本引用。

使用 ScriptManager 控件的註冊方法,可以註冊部分頁更新所需的腳本。您可以按下列方式使用這些方法:

·若要在代碼中生成客戶端腳本,請以字符串形式生成一個腳本塊,然後將其傳遞給 RegisterClientScriptBlock 方法。

·若要添加沒有 Microsoft AJAX Library 依賴項的獨立腳本文件,請使用 RegisterClientScriptInclude 方法。

·若要添加嵌入在程序集中的腳本文件,請使用 RegisterClientScriptInclude 方法。

      任何要註冊的腳本塊或內聯腳本都必須位於頁面的 <form> 元素中。否則,該腳本將不能在 ScriptManager 控件中註冊,從而無法訪問 ASP.NET AJAX 功能。

 

發佈了247 篇原創文章 · 獲贊 15 · 訪問量 51萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章