让我们先来理解“全局”二字的含义。
HTML页面可以定义客户端脚本,为页面外观提供丰富的可视化行为和逻辑,客户端脚本可以写在<head>或<body>中。写在<head>中的脚本就是文本所指的“全局”脚本,为什么说它是全局的呢?因为<head>中定义的客户端脚本函数可以在<body>中任何地方被访问,而在<head>中函数外部定义的客户端脚本,也能在页面加载后的第一时间,按顺序被浏览器执行,而且能够访问页面中的全部对象。相对的,<body>中的脚本只能按顺序执行,其中定义的函数只能被其后的客户端脚本调用,其访问的页面对象也必须在其之前定义。
由于MasterPages无法正确输出<head>中定义的Region/Content,那么为每一个窗体提供客户端全局脚本注册的任务,同样落在了模板控件的Page_Load事件处理函数身上。
首先,在模板控件中定义<region>(控件代码头部注册Tag部分略,请参考前文):
<body>
<form id="form1" runat="server">
...
<mp:region id="regScript" runat="server"></mp:region>
...
</form>
</body>
然后,在模板控件的Page_Load事件处理函数内添加代码:
if (regScript.Controls.Count > 0)
{
System.Web.UI.LiteralControl script = (System.Web.UI.LiteralControl)regScript.Controls[0].Controls[0]; // MasterPages会将content中的内容以LiteralControl放入一个Panel,而把这个Panel再放入region
this.Page.RegisterClientScriptBlock("client_script", script.Text);
}
RegisterClientScriptBlock是Page类中的一个方法,作用是为窗体注册客户端全局脚本,它有两个参数:第一个参数指定所注册的脚本段名称,如果窗体内已存在同名脚本段,则会替换现有的脚本;第二个参数就是索要注册的脚本内容,必须是完整的包含<script>标记的脚本。
接下来,我们就可以在应用此模板的窗体中定义其自身的客户端全局脚本了:
<mp:contentcontainer runat="server" MasterPageFile="~/Template.ascx" id="Test">
<mp:content id="regTitle" runat="server">Test页面标题</mp:content>
<mp:content id="regScript" runat="server">
<script language="javascript">
function test()
{
alert("Hello World!");
}
</script>
</mp:content>
<mp:content id="regContent" runat="server">窗体内容测试</mp:content>
</mp:contentcontainer>
从“MasterPages实用技巧”的下一篇开始,我们将不再使用MasterPages,而使用WilsonMasterPages。这是一个免费的MasterPages替代品,它对MasterPages做了改进,修正了MasterPages的一个严重Bug(请参考文章“MasterPage之超严重Bug——将导致窗体内带有回发事件的控件无法回发事件——以及解决方案”。
在下一篇里,你可以了解基于MasterPages的又一个模板前端控制技巧——为窗体添加一个“返回”按钮。
希望能给大家带来帮助,谢谢!