写一个给按钮、链接等控件增加快捷键的控件
肯定有这样子的需求:我们希望能用快捷键代替鼠标点击做一些事情,例如一个典型的应用就是论坛上常用的Ctrl + Enter 快捷发帖子。就以Ctrl+Enter快捷发帖子为例,实质上呢,就是通过js脚本,捕获系统的onkeyup事件,判断event.ctrlKey是否为true并且event.keyCode为13,如果满足这个条件,那么就调用按钮对象的click()方法,等同于用鼠标去点击按钮。写个简单的示例代码:
<html>
<head>
<title> 快捷键提交示例代码 </title>
<link rel="stylesheet" href='css/style.css' type="text/css">
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
<meta name="author" content="宝玉" />
<script language="JavaScript" type="text/javascript">
<!--
// 快捷键响应
// targetObj: 目标对象,如果满足快捷键条件,触发目标对象的click事件
// ctrlKey: 是否按住了Ctrl组合键
// shiftKey: 是否按住了Shift组合键
// altKey: 是否按住了Alt组合键
// keycode: 按键对应的数值
function Hotkey(event, targetObj, ctrlKey, shiftKey, altKey, keycode)
{
if (
targetObj
&& event.ctrlKey == ctrlKey
&& event.shiftKey == shiftKey
&& event.altKey == altKey
&& event.keyCode == keycode
)
targetObj.click();
}
function fnKeyup(event)
{
var b = document.getElementById("myButton");
Hotkey(event, b, true, false, false, 13);
}
// 捕获系统的Keyup事件
// 如果是Mozilla系列浏览器
if (document.addEventListener)
document.addEventListener("keyup",fnKeyup,true);
else
document.attachEvent("onkeyup",fnKeyup);
//-->
</script>
</head>
<body>
<form method="get" action="no.aspx">
<input type="submit" id="myButton"/>
Ctrl + Enter
</form>
</body>
</html>
上面的脚本可以方便的给指定的按钮加上快捷键。如果现在我们希望应用到我们的服务器端控件当中去,例如Button、Linkbutton、Hyperlink等,因为控件的ID各不相同,而且所对应的快捷键也各不相同,那么我们就需要写一个控件来给他们添加快捷键了。
想想这个控件需要哪些属性?
TargetControlID:string:既然是给其他控件绑定的,那么所要绑定的目标控件ID是少不了了,根据这个控件ID,我们才能确定一个控件,才能知道它输出时的客户端ID,才能根据客户端ID来在脚本里面确定这个对象。
CtrlKey:bool:判断是否用到Ctrl组合键
ShiftKey:bool:判断是否用到Shift组合键
AltKey:bool:判断是否用到Alt组合键
KeyCode:int:和DHTML里面的event.keyCode对应的,例如Enter的keyCode是13。(注:其实这个不是很友好,因为用的时候还要找一下键盘各个按键和keyCode的对应关系,如果结合一个快捷键设置的控件就比较完美了)
Text:string:可能顺便需要一点文字说明什么的
相对来说,这是一个比较简单的用户自定义控件应用,创建一个名字为HotKey的类,继承自System.Web.UI.Controls。根据目标控件ID查找控件对象:this.cachedTargetControl = this.NamingContainer.FindControl(this.TargetControlID);
根据上面属性,我们就可以生成相应的客户端脚本了,然后在重写控件的OnPreRender事件中使用RegisterClientScriptBlock方法输出脚本。
代码相对比较简单:
using System;
using System.ComponentModel;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.Design;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
namespace CommunityServer.Controls
{
/// <summary>
/// hotkey
/// author: dotey
/// http://www.communityserver.cn
/// </summary>
public class Hotkey : Control
{
private static readonly String scriptKey = "CommunityServer.Controls.Hotkey";
public Hotkey()
{
}
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender (e);
string hotkeyFunctionScript = @"
<script>
function Hotkey(event, targetObj, ctrlKey, shiftKey, altKey, keycode)
{
if (
targetObj
&& event.ctrlKey == ctrlKey
&& event.shiftKey == shiftKey
&& event.altKey == altKey
&& event.keyCode == keycode
)
targetObj.click();
}
</script>
";
if ( !Page.IsClientScriptBlockRegistered( scriptKey ) )
{
this.Page.RegisterClientScriptBlock( scriptKey, hotkeyFunctionScript );
}
string key = scriptKey + "-" + targetControl.ClientID;
if ( targetControl != null && !Page.IsClientScriptBlockRegistered( key ) )
{
this.Page.RegisterClientScriptBlock( key, CreateScript() );
}
}
protected override void Render(HtmlTextWriter writer)
{
base.Render (writer);
writer.Write(this.Text);
}
/// <summary>
/// 根据属性生成相关脚本
/// </summary>
/// <returns></returns>
private string CreateScript()
{
if ( targetControl == null )
return "";
string functionName = string.Format("fn{0}Keyup", targetControl.ClientID);
StringBuilder s = new StringBuilder();
s.Append("<script>\n");
s.AppendFormat("function {0}(event)\n", functionName);
s.Append("{\n");
s.AppendFormat("\tvar b = document.getElementById('{0}');\n", targetControl.ClientID);
s.AppendFormat("\tHotkey(event, b, {0}, {1}, {2}, {3});\n",
this.CtrlKey.ToString().ToLower(),
this.ShiftKey.ToString().ToLower(),
this.AltKey.ToString().ToLower(),
this.KeyCode
);
s.Append("}\n");
s.Append("if (document.addEventListener)\n");
s.AppendFormat("\tdocument.addEventListener('keyup', {0}, true);\n", functionName);
s.Append("else\n");
s.AppendFormat("\tdocument.attachEvent('onkeyup', {0});\n", functionName);
s.Append("</script>\n");
return s.ToString();
}
/// <summary>
/// 目标控件
/// </summary>
[
Category("Behavior"),
DefaultValue(""),
]
public virtual String TargetControlID
{
get
{
object savedState = this.ViewState["TargetControlID"];
if ( savedState != null )
{
return (String)savedState;
}
return "";
}
set
{
this.ViewState["TargetControlID"] = value;
this.cachedTargetControl = null;
}
}
/// <summary>
/// 根据目标控件的ID来找目标控件对象
/// </summary>
private Control targetControl
{
get
{
if ( cachedTargetControl == null )
{
this.cachedTargetControl = this.NamingContainer.FindControl(this.TargetControlID);
}
return this.cachedTargetControl;
}
}
private Control cachedTargetControl = null;
/// <summary>
/// 文字说明
/// </summary>
[
System.ComponentModel.DefaultValue( "Caption" ),
]
public virtual String Text
{
get
{
Object state = ViewState["Text"];
if ( state != null )
{
return (String)state;
}
return "";
}
set
{
ViewState["Text"] = value;
}
}
/// <summary>
/// 和DHTML里面的event.keyCode对应的,例如Enter的keyCode是13。
/// </summary>
/// <remarks>
/// 其实这个不是很友好,因为用的时候还要找一下键盘各个按键和keyCode的对应关系,如果结合一个快捷键设置的控件就比较完美了
/// </remarks>
public int KeyCode
{
get
{
int keyCode = 0;
try
{
keyCode = Convert.ToInt32(ViewState["KeyCode"]);
}
catch{}
return keyCode;
}
set
{
ViewState["KeyCode"] = value;
}
}
/// <summary>
/// 是否使用Alt复合键
/// </summary>
public bool AltKey
{
get
{
Object state = ViewState["AltKey"];
if ( state != null )
{
return (Boolean)state;
}
return false;
}
set
{
ViewState["AltKey"] = value;
}
}
/// <summary>
/// 是否使用Shift复合键
/// </summary>
public bool ShiftKey
{
get
{
Object state = ViewState["ShiftKey"];
if ( state != null )
{
return (Boolean)state;
}
return false;
}
set
{
ViewState["ShiftKey"] = value;
}
}
/// <summary>
/// 是否使用Ctrl复合键
/// </summary>
public bool CtrlKey
{
get
{
Object state = ViewState["CtrlKey"];
if ( state != null )
{
return (Boolean)state;
}
return false;
}
set
{
ViewState["CtrlKey"] = value;
}
}
}
}
最后,调用的时候就比较方便了:
和普通的自定义用户控件一样:
<asp:Button Runat="server" id="PostButton" CssClass="txt3"></asp:Button>
<cs:Hotkey runat="server" TargetControlID="PostButton" KeyCode="13" CtrlKey="True" Text="(Ctrl + Enter)"/>