使用 JQuery 进行带持久化的拖放
如何创建拖放功能将用户添加到房间
引言
您是否曾经在网站上看到过拖放操作?它可能允许您将产品拖放到购物车中。我们大多数人都体验过,并且对这项功能印象深刻。在本文中,我们将重点介绍如何创建类似的拖放功能,将用户添加到房间。
为什么选择 JQuery?
为什么确实要选择 JQuery?市面上有许多免费的拖放库。例如,可以使用 Microsoft ASP.NET Ajax。不幸的是,Microsoft Ajax 库对开发者来说并不友好,也就是说,它非常复杂。所以,如果您正在寻找一些令人头疼的体验,请务必深入研究 Microsoft Ajax。但是,如果您对简单而强大的方法感兴趣,那么 JQuery 就是您的朋友。
有些人可能会想,“为什么不直接编写普通的 JavaScript 呢?” 当然可以,但这同样是一个非常复杂且耗时的过程。如果您只想使用 JavaScript,请参阅文章“浏览器兼容的拖放购物车”。
下载 JQuery 和 UI API
在实现任何功能之前,我们需要下载 JQuery 库和 JQuery 拖放 UI API。请查看以下链接进行下载:
场景
这个场景与购物车略有不同。在此应用程序中,我们将把用户拖放到一个房间。一旦用户被添加到房间,就会向数据库写入一条记录。我们也可以从房间中删除用户。在这种情况下,数据库中的记录也会被删除。请查看 GIF,链接为“使用 JQuery 实现带持久化的拖放”。
数据库
有一个名为 tblRoomSessions 的表,它将保存有关用户和房间的信息。下面显示了 tblRoomSessions 表的图示。
 
 
表脚本包含在下载文件中。
填充学生列表
有多种方法可以填充学生 DataList 控件。您可以使用简单的 DataSet 容器,将其填充来自 tblRoomSession 的数据,然后将其分配给 DataList 控件。我使用了不同的方法,但这实际上并不影响如何填充 DataList。
学生 DataList 控件 ASPX 代码
DataList 控件的 ASPX 代码非常直接。请查看下面的代码:
<asp:DataList ID="dlRooms" EnableViewState="false" runat="server" RepeatColumns="3"
            RepeatDirection="Horizontal">
    <ItemTemplate>
    <div id="div1" class="block">
    <div style="text-align:center; font-size:18px; border:solid 1px">
        <%# Container.ItemIndex + 1 %></div><li id="username" runat="server">
    <%# Eval("UserName") %></li><li id="roomId" runat="server" style="visibility:hidden">
    <%# Eval("RoomID") %></li><li>
    <%# Eval("Subject") %></li><li>
    <%# Eval("Description") %></li></div></ItemTemplate></asp:DataList>
当 DataList 被填充后,它看起来会像下面的截图:
 
 
数字表示学生请求房间的顺序。这意味着学号为 1 的学生比学号为 2 的学生先请求房间。这些数字是使用以下语句生成的:
<%# Container.ItemIndex + 1 %>
您还会注意到,ID 为 roomId 的 <LI> 被标记为 hidden。您无需在每个 <LI> 中嵌入 roomId,因为您在到达此页面之前就知道 roomId。包含所有 <LI> 的 <DIV> 元素具有一个名为 block 的类。让我们在下一节中看看所有的样式。
CSS 样式
此应用程序使用了多种 CSS 样式。让我们看其中一些。
.block {
   border: 2px solid #0090DF;
   background-color: #68BFEF;
   width: 200px;
   height: 200px;
   margin: 10px;
   overflow:auto;
   padding:1em 1em 1em 1em;
   z-index:9999;
   cursor:move;
}
block 样式用于所有可拖动的项。
.roomItem {
   border: 2px solid #0090DF;
   background-color: yellow;
}
roomItem 样式用于添加到房间的项。
.drop {
 background-color: #e9b96e;
 border: 3px double #c17d11;
   width: 300px;
   height: 300px;
   margin: 10px;
   overflow:auto;
   position:absolute;
  top: 5px;
  right: 10%;
  padding: 1em 0 0 0;
}
drop 样式用于放置区域 <DIV> 元素,在本例中是房间。
使用 JQuery 使项可拖放
我将首先发布完整的代码,然后分段解释代码。
$(document).ready(function(){
    $(".block").draggable({helper:'clone'});
    $(".drop").droppable({
 accept: ".block",
 activeClass: 'droppable-active',
 hoverClass: 'droppable-hover',
 drop: function(ev, ui) {
 $(ui.draggable).addClass("roomItem");
 var lid = ($(ui.draggable).children("li:first"));
 // gets the username
 var username = ($(ui.draggable).children("li:first").text()).replace(/[\n\r\t]/g,'');
 var roomId = $(ui.draggable).children("li:eq(1)").text();
 var removeLink = document.createElement("a");
 removeLink.innerHTML = "remove";
 removeLink.href = "#";
 removeLink.onclick = function()
 {
      $("#drop1").children().remove("#"+lid[0].id);
      $(this).remove();
      // removes the class
      $(ui.draggable).removeClass("roomItem");
      // adds the new class
      $(ui.draggable).addClass("block");
      // remove the user session from the database
      VirtualTutoringRoomWebApps.VirtualRoomService.removeUserFromRoom(
          username,Number(roomId));
 }
 $(this).append($(ui.draggable).clone().children("li:first").addClass("roomItem"));
 $(this).append(removeLink);
 // add user to the room
 VirtualTutoringRoomWebApps.VirtualRoomService.addUserToRoom(username,Number(roomId));
 }
});
  });
看起来很复杂!别担心;并不难理解。让我们从 document.ready 函数开始,该函数在 DOM(文档对象模型)准备好并加载后触发。
要使元素可拖动,您只需要使用 JQuery UI API 提供的 draggable 函数。该函数可以接受不同的参数,但我们使用了类的名称,在本例中是 .block。这意味着“使所有类为 .block 的元素可拖动”。draggable 函数还接受 helper。Helper 用于对可拖动项执行操作。我们正在使用 clone helper,它将为我们的可拖动项创建一个 clone。
$(".block").draggable({helper:'clone'});
创建放置区域也使用了相同的技术。当项被放到放置区域内时,一个名为 roomItem 的类会被添加到该项。这会给该项应用黄色背景,表明该项已被放入放置区域。然后,我们使用以下代码从可拖动的 <DIV> 元素内的 <LI> 项中提取 username 和 roomId。
// gets the username
 var username = ($(ui.draggable).children("li:first").text()).replace(/[\n\r\t]/g,'');
 var roomId = $(ui.draggable).children("li:eq(1)").text();
创建了一个新的超链接元素,用于从放置区域中删除项。基本上,remove 链接用于将用户从房间中移除。
var removeLink = document.createElement("a");
 removeLink.innerHTML = "remove";
 removeLink.href = "#";
 removeLink.onclick = function()
 {
      $("#drop1").children().remove("#"+lid[0].id);
      $(this).remove();
      // removes the class
      $(ui.draggable).removeClass("roomItem");
      // adds the new class
      $(ui.draggable).addClass("block");
      // remove the user session from the database
      VirtualTutoringRoomWebApps.VirtualRoomService.removeUserFromRoom(
          username,Number(roomId));
 }
当项从放置区域移除时,它会返回到其原始类,即 block。服务器端 removeUserFromRoom 方法被触发,该方法将项从数据库中移除。我们将在本文稍后介绍此方法。当我们拖放项到放置区域时,我们将第一个 <LI> 元素附加到放置区域。在本例中,这是用户的 username。
$(this).append($(ui.draggable).clone().children("li:first").addClass("roomItem"));
 $(this).append(removeLink);
 // add user to the room
 VirtualTutoringRoomWebApps.VirtualRoomService.addUserToRoom(username,Number(roomId));
请查看下面的截图,显示了添加到放置区域的项。
 
 
最后,addUserToRoom 方法被触发,并将用户添加到房间。
Ajax 方法
我使用了 Microsoft ASP.NET Ajax 来创建到 Web 服务方法的异步调用。让我们看看这些方法:
[WebMethod]
        public bool removeUserFromRoom(string username, int roomId)
        {
            MethodInvoker.Invoke<SQLDataAccess>("RemoveUserFromRoom", new object[]
            {
                username.Trim(), roomId
            });
            return false;
        }
        [WebMethod]
        public bool addUserToRoom(string username, int roomId)
        {
            try
            {
                MethodInvoker.Invoke<SQLDataAccess>(
                    typeof(tblRoomSession), "AddAndPersistAll",
                    new object[]
                    {
                        new tblRoomSession()
                        {
                            Guid = Guid.NewGuid().ToString(), RoomID = roomId,
                            StudentUserName = username.Trim(),
                            TutorUserName = User.Identity.Name, IsSessionStarted = true,
                            SessionStartDate = DateTime.Now
                        }
                    });
            }
            catch (Exception ex)
            {
                string exception = ex.Message;
            }
            return false;
        }
不要太在意 MethodInvoker 类。这是一个自定义类,用于在对象上创建数据访问操作。您可以使用 DataSet、Entity 类、Manager、Repository 和 Mapper 来执行数据访问操作。如果您对 MethodInvoker 类感兴趣,请参阅博文“MethodInvoker”。
附加功能
此应用程序还需要实现一些额外的功能。其中一些列在下面:
- 一个计时器,它将异步获取等待房间的用户,而无需刷新页面。
- 不允许将重复用户添加到同一个房间。
更新
在发布时,我们讨论了一些可能有用的附加功能。其中一些显示在上面的“附加功能”部分。这里实现了这两个功能。
首先,让我们看看当新用户进入等待列表时如何更新界面。这个过程应该是异步的,这意味着屏幕不应在服务器端刷新,而应在客户端刷新。事实证明,这可以通过使用 ASP.NET Timer 控件轻松完成。Timer 控件将触发一个事件,该事件将触发服务器端的一个方法。首先,您需要在 UpdatePanel 控件内添加 Triggers 部分。
 <triggers>
     <asyncpostbacktrigger eventname="Tick" controlid="timer1">
     </triggers>
现在,让我们看看同样包含在 UpdatePanel 控件内的 Timer 控件。
<timer id="timer1" ontick="timer1_Tick" interval="5000" runat="server" />
Timer 控件每 5 秒触发一次 timer1_Tick 事件。现在,让我们看看 timer1_Tick 事件:
  protected void timer1_Tick(object sender, EventArgs e)
        {
            BindData();
            up1.Update();        }
这很简单!timer1_Tick 事件通过 BindData 方法从数据库获取数据,然后刷新 UpdatePanel 以更新用户界面。一切运行良好……持续 5 秒。5 秒后,您将无法拖放您的对象。
原因在于,当您使用 UpdatePanel 更新屏幕时,它会重置其中的所有控件。现在,您可以看到控件,但它们没有任何功能。有一个简单的方法可以解决这个问题。您所要做的就是再次使元素可拖动。请查看下面的实现:
protected void timer1_Tick(object sender, EventArgs e)
        {
            BindData();
            up1.Update();
            RegisterDragAndDropScript();
        }
        // this method is fired to register the scripts again 
        // since the timer will refresh the contents of the
        // update panel and hence the HTML controls will lose 
        // the drag and drop capability
        private void RegisterDragAndDropScript()
        {
            string script = "makeElementsDraggableAndDroppable();";
            ScriptManager.RegisterClientScriptBlock(this,this.GetType(),
                "DragAndDropScript", script, true);
        }
现在,当 UpdatePanel 刷新时,控件再次变得可拖动。
结论
在本文中,我们学习了如何使用 JQuery 和 JQuery UI API 创建拖放 UI。希望您喜欢这篇文章;祝您编码愉快!
历史
- 2008 年 3 月 5 日 -- 最初版本发布
- 2008 年 3 月 7 日 -- 文章更新




