(翻译)用ASP.NET AJAX实现无缝行内文本编辑框

首先,谢谢TerryLee推荐系列,本文就是在他的推荐系列看到的.

原文:Seamless inline text editing with ASP.NET AJAX

在开始之前,我们需要一个web form显示这个行内文本Label和一个隐藏的TextBox会在编制的时候用来替换的:

<asp:ScriptManager ID="ScriptManager1" runat="server" 
  EnablePageMethods
="true">
  
<scripts>
    
<asp:ScriptReference Path="behaviors.js" />
  </scripts>
</asp>
<asp:Label runat="server" ID="Label1" />
<asp:TextBox runat="server" ID="TextBox1" Style="display: none;" />

请主意,我没有使用TextBox的"Visibility"属性来隐藏它,而是使用CSS来隐藏它.这点很重要,因为ASP.NET不会为一个隐藏的服务器控件生成HTML代码,这会使它无法在客户端操控.

为了方便演示,我将用Cache来填充我们的Label.你也可以很容易的使用数据库,文件,或者其他的存储数据来代替.

protected void Page_Load(object sender, EventArgs e)
{
  
if (Cache["Title"!= null)
    Label1.Text 
= Cache["Title"].ToString();
  
else
    Label1.Text 
= "Default Title (click to edit)";
}

使用JavaScript来切换显示

首先,我们需要一个Application Init handler来建立Label和TextBox的客户端事件处理器.

>下面所有的代码块都是包含在 behaviors.js 中的.

var Label1, TextBox1;   Sys.Application.add_init(AppInit);
function AppInit(sender) {
  Label1 
= $get('Label1');
  TextBox1 
= $get('TextBox1');
  $addHandler(Label1, 
"click", Label1_Click);
  $addHandler(TextBox1, 
"blur", TextBox1_Blur);
  $addHandler(TextBox1, 
"keydown",   TextBox1_KeyDown);
}

除了写好了事件处理器,我还创建了一对全局变量来保存对Label和TextBox元素的引用.这避免过多的调用 $get(),这样多少能改善程序的易读性.

接下来,让我们来处理Label的click事件:

function Label1_Click() {
  TextBox1.value 
= Label1.innerHTML;
Label1.style.display 
= 'none';
TextBox1.style.display 
= '';  // Thanks,Ira.
TextBox1.focus();
}

这里发生一些事情:

  • 首先,确保所有的东西在同步的情况下,在显示TextBox之前总是将Label的当前值赋给它.
  • 然后,我们通过切换两个元素的display属性,我们高效的将Label切换为TextBox.
  • 最后,使用TextBox的focus()方法,使鼠标定位到新显示的的TextBox中.

这一连串的事件创建了一个直观的用户体验.就好像只是简单的点击了文本就将鼠标置于其中的TextBox中去了.

下一步,我们将处理TextBox的blur(失去焦点)事件:

function TextBox1_Blur() {  
  Label1.innerHTML 
= TextBox1.value;
TextBox1.style.display 
= 'none';
Label1.style.display 
= '';// Thanks, Ira.
}

这里用TextBox的新值去更新Label的值,然后切换两个元素的可见性.这只是和Label1_Click()方法相反而已.

响应回车键

一个有问题的情况是当用户在编辑的时候按下回车键.在TextBox中按下回车键会提交表单并产生一个不希望发生的postback.而事实上,这个情况应该跟用户完成编辑时将鼠标的焦点离开TextBox是一样的.

幸运的,解决方法很简单:

function TextBox1_KeyDown(event) {
  
if (event.keyCode == 13) {
event.preventDefault();
// Thanks, Alessandro.
TextBox1.blur();
  }
}

这里所做的是拦截按下回车键的时候,并取消提交表单,然后使TextBox失去焦点,而使所有的东西都按我们期望的进行.

在任何人察觉到它消失前将它返回

如果我们不以某种方式将修改的内容保存回服务器中,这就没有价值了.当然,UpdataPanel和_doPostBack()结合是一种保存的途径,通过部分postback.

然而,我认为使用JSON和页面方法是另外一个更好的解决方法.

首先,我们需要一个静态的方法来保存我们的数据.正如我刚才所说,为了简便我使用Cache,但在你的代码中你可以很容易的更新一个数据库字段或者写入到文件中.

[WebMethod]
public static void SetTitle(string title)
{
  HttpContext.Current.Cache[
"Title"= title;
}

好,现在我们已经有一个途径来保存我们的数据了.现在,我们所要做的就是修改我们的TextBox的"blur"事件处理程序来使用它:

function TextBox1_Blur() {   
  Label1.innerHTML 
= TextBox1.value;
TextBox1.style.display 
= 'none';
Label1.style.display 
= 'inline';
PageMethods.SetTitle(TextBox1.value);
}

就是这么简单

注意到页面上一个UpdatePanel都没有.那东西并不是必须的.使用JSON使这件工作很快,很高效.

如何使它更好

这只是开始.一些潜在的改进的地方包括:

  • 当TextBox失去焦点的时候检查TextBox的内容,只有当确实修改过TextBox的内容的时候才调用SetTitle() .
  • 如果使用一个比较慢的数据存储,使用进度条可能是有利的.
  • 使用一些分类的背景图片来指示某些内容是可以进行行内编辑的.
  • 处理ESC键(27)来取消编辑并返回到Label,而没有改变Label的内容.

 

源代码下载:

点此下载源代码

posted on 2008-01-15 04:16  Q.Lee.lulu  阅读(1185)  评论(1编辑  收藏  举报