代码改变世界

简单但完整的树形列表+多选(复选)框实现方式

2010-07-09 01:25  watsonchia  阅读(4169)  评论(0编辑  收藏  举报

多级分类通常做成树形的,如果分类是单选的,只要递归返回树形结构,用下拉列表显示就ok了。当分类要求多选的时候,我们需要给每个分类都加上复选框。在Asp.Net里TreeView可以显而易见的做到这个,然而TreeView服务端控件不但生成比较ugly的html代码,而且所需写代码的时候其实也并不是最少。下面给出我的一个简单(代码数较少)但是完整的实现方式,除了显示,还包括取得选中值以及对树形列表赋值 。需要达到的效果如下,点击一个span可展开或收起树形列表。

我选择用ul显示树形列表,这也是一个常用的方式。下面是aspx页面的代码,用jquery编写相关的脚本。
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <style type="text/css">
        body { font-size: 12px; font-family: Verdana, 微软雅黑; }
        ul { margin: 0px 10px; padding: 0px 10px; list-style: none; }
        li { line-height: 16px; }
    </style>
    <script src="Scripts/jquery.js" type="text/javascript"></script>
    <script type="text/javascript">
        //选中itemList里的保存Id的Checkbox
        function checkItems(nodeName, itemList) {
            var arr = itemList.split(',');
            $.each(arr, function (i, n) {
                $("#" + nodeName + "-" + arr[i]).attr("checked", "checked");
            });
        }

        $(function () {
            //点击展开或收起树形列表
            $("#spCategory").click(function (event) {
                event.stopPropagation();
                var offset = $(this).offset();
                $('#ulCategory').css({ left: offset.left, top: offset.top + 30 }).toggle();
            });

            //取消弹出层本身冒泡事件
            $("#ulCategory").click(function (event) { event.stopPropagation(); });

            //点击页面其他位置使弹出层消失
            $(document).click(function () { $("#ulCategory").hide(); });
        });
    </script>
</head>
<body>
    <span id="spCategory" style="border: solid 1px silver; line-height: 25px; padding: 3px 5px; cursor: pointer; float: left;">点击这里展开或收起分类</span>
    <ul id="ulCategory" style="position: absolute; background-color: ActiveCaption; display: none;">
        <asp:Literal ID="ltrCategory" runat="server"></asp:Literal>
    </ul>
</body>
</html>

后台cs代码如下,主要是返回树形结构。

public partial class _Default : System.Web.UI.Page 
{
    protected void Page_Load(object sender, EventArgs e)
    {
        DataSet ds = new DataSet();
        ds.ReadXml(Server.MapPath("Category.xml"));
        ltrCategory.Text = GetTreeHtml(ds.Tables[0], "category");
    }

    string GetTreeHtml(DataTable dt, string nodeName)
    {
        StringBuilder sb = new StringBuilder();
        DataView dv = new DataView(dt);
        dv.RowFilter = "ParentId = 0";
        foreach (DataRowView rv in dv)
        {
            sb.Append("<li>");
            sb.AppendFormat("<label><input type='checkbox' id='{0}-{1}' name='{0}' value='{1}' />{2}</label>", nodeName, rv["Id"], rv["Name"]);
            AddChild(sb, dt, rv, nodeName);
            sb.Append("</li>");
        }

        return sb.ToString();
    }

    void AddChild(StringBuilder sb, DataTable dt, DataRowView drv, string nodeName)
    {
        DataView dv = new DataView(dt);
        dv.RowFilter = string.Format("ParentId = {0}", drv["Id"]);

        if (dv.Count > 0)
            sb.Append("<ul>");
        else
            return;

        foreach (DataRowView rv in dv)
        {
            sb.Append("<li>");
            sb.AppendFormat("<label><input type='checkbox' id='{0}-{1}' name='{0}' value='{1}' />{2}</label>", nodeName, rv["Id"], rv["Name"]);
            AddChild(sb, dt, rv, nodeName);
            sb.Append("</li>");
        }
        sb.Append("</ul>");
    }
}

代码里返回树形html的方法是GetTreeHtml,两个参数,分别是保持分类信息的datatable,以及checkbox的name。如上代码里,checkbox的name为category,则提交到后台时可以使用

Request.Form["category"]

取得选中值,而且是已序列化好的。比如选中了Id为1,2,3的三个分类的checkbox,则取得值为:1,2,3。而把这个序列赋值到树形列表上,只要简单的调用aspx里的一个js函数checkItems(nodeName, itemList),如

checkItems('category', '1,2,3')

相比TreeView服务端控件,不但生成的html更干净,而且所写总的代码行数也更少,当然js代码行数少是因为使用jquery的缘故 -)

以上demo代码里使用xml保存多级分类数据,包括三个字段,分类Id、父类Id,分类名称,如下

<?xml version="1.0" encoding="utf-8" ?>
<Categories>
  <Category Id="1" ParentId="0" Name="首页"></Category>
  <Category Id="2" ParentId="1" Name="政策法规"></Category>
  <Category Id="3" ParentId="1" Name="行政公告"></Category>
  <Category Id="4" ParentId="0" Name="新闻中心"></Category>
  <Category Id="5" ParentId="2" Name="政策"></Category>
  <Category Id="6" ParentId="2" Name="法规"></Category>
</Categories>