• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
vs之bug
博客园    首页    新随笔    联系   管理    订阅  订阅

基于asp.net ajax 的异步加载无限级联树状菜单

  最近一个项目用到这个功能,本来以为很容易,但写起来发现还是有点小难度的,现在写出来分享,如果不好不要拍砖~

  效果图 1

  

  效果图 2

  

  效果图 3

  

  一:数据库设计

 

    数据字典:

    menuID:自增列

    menuName:菜单名

    url:菜单指向

    parentID:父级菜单ID,根目录为 0

    menuIndex:菜单排序ID

    menuLevel:菜单级别,根级别为 0

    menuImg:菜单图片

 

  二:数据实体类 

    需要这个类是为了前台操作的方便,这里要感慨微软的ajax框架确实功能强大,通过它,在前台用Javascript可以很方便的操作。这个类对应于数据表,非常简单。

    

代码
    /// <summary>
    
/// 菜单信息类
    
/// </summary>
    [Serializable]
    
public class MenuInfo
    {
        
public int MenuId { get; set; }
        
public string MenuName { get; set; }
        
public string Url { get; set; }
        
public int ParentId { get; set; }
        
public int MenuIndex { get; set; }
        
public int MenuLevel { get; set; }
        
public int ChildCount { get; set; }

        
public MenuInfo() { }
    }


     如果是VS2008,可以不用加 [Serializable] 特性。

  三:数据库操作类

     因为是异步加载,点击菜单项时才会加载下一级的菜单,所以sql 语句根据传入的parentID来检索数据。

    

        /// <summary>
        
/// 根据parentId 分级获取菜单,用于Ajax加载模式
        
/// </summary>
        
/// <param name="parentId"></param>
        
/// <returns></returns>
        public List<MenuInfo> GetChildMenus(int parentId)
        {
            
string commandText = @"
                                select 
                                    [menuId],
                                    [menuName],
                                    [url],
                                    [parentId],
                                    [MenuIndex],
                                    [MenuLevel],
                                    (select count(0) from b_Menu f where f.parentid= m.menuId)as ChildCount
                                from 
                                    b_Menu m 
                                where 
                                    parentid=@parentId ORDER BY MenuIndex
";
            DbParameter[] parms 
=
            {
                DBSQLHelper.MakeInParam(
"@parentId",(DbType)SqlDbType.Int,parentId)
            };
            
return LoadMenuInfo(DBSQLHelper.ExecuteReader(CommandType.Text, commandText, parms));
        }

 

       

        private List<MenuInfo> LoadMenuInfo(IDataReader dr)
        {
            List<MenuInfo> menuList = new List<MenuInfo>();
            while (dr.Read())
            {
                MenuInfo m = new MenuInfo();
                m.MenuId = TypeParse.ObjectToInt(dr["menuid"]);
                m.MenuName = dr["menuName"].ToString().Trim();
                m.ParentId = TypeParse.ObjectToInt(dr["parentId"]);
                m.Url = dr["url"].ToString();
                if (dr.GetSchemaTable().Rows[6][0].ToString() ==("ChildCount"))
                {
                    m.ChildCount = TypeParse.ObjectToInt(dr["ChildCount"]);
                }
                m.MenuIndex = TypeParse.ObjectToInt(dr["MenuIndex"]);
                m.MenuLevel = TypeParse.ObjectToInt(dr["MenuLevel"]);
                menuList.Add(m);
            }
            dr.Close();
            return menuList;
        }

 


  四:使用WebService调用数据类

           ScriptManager控件对Javascript调用webservice有非常好的支持
           使用webservice是为了让javascript可以比较容易的调用,注意在webservice的开头要添加
[System.Web.Script.Services.ScriptService] 特性。
当然,你也可以把ScriptManager控件的 EnablePageMethods 属性设为 true 后将方法写在 .aspx.cs 文件里,然后在 页面中用 PageMethods.GetChildMenus调用。

 

          

代码
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo 
= WsiProfiles.BasicProfile1_1)]
[System.Web.Script.Services.ScriptService]

public class BGMService  : System.Web.Services.WebService {

    
public BGMService() {
 
    }
}


          

    [WebMethod]
    
public List<MenuInfo> GetChildMenus(string parentId)
    {
        
//System.Threading.Thread.Sleep(1000);
        return Menu.GetChildMenu(parentId);
    }


  五:JavaScript接受数据 

           前面已经说了,asp.net ajax 对javascript调用webservice有很好的支持,具体怎么做呢?

           1.将 ScriptManager 控件拖到页面上。

           2.设置webservice引用地址

    <Services>
        
<asp:ServiceReference Path="~/BackManageMent/webservice/BGMService.asmx" />
    
</Services>

          然后在javascript 中就可以用  类名.方法名()  调用了。在本列中就是 BGMService.GetChildMenus() 。简单吧。

          接到数据之后的处理比较麻烦,需要一定的javascript功底。我先把代码贴出来,有时间在加注释。

         

代码
div #treeMenus div{border:0;}
div #treeMenus img
{cursor:pointer;}
div #treeMenus .Level_1
{
    margin
:0;
    padding
:0;
}
div #treeMenus .Level_2
{
    margin
:0;
    padding
:0;
    
}
div #treeMenus .machn
{
    margin
:0;
    margin-left
:40px;
    padding
:0;
    
}
div #treeMenus ul
{
    list-style-type
:none;
    width
:100%;
    height
:auto;
    clear
:both;
}
div #treeMenus ul li
{
    list-style-image
:none;
    float
:left;
    margin-right
:4px;
}
div #treeMenus ul .li_txt
{
    padding-top
:4px;
    cursor
:pointer;
}
div #treeMenus ul .li_txt:hover
{
    text-decoration
:underline;
}


 

代码
var tree = function()
{
    
var _self=this;
    BGMService.GetChildMenus(
"0",function(value){onGetTree(value,frame.treeMenus)},onFailure);//在asp.net Ajax的回调函数中传递自定义参数的方法
    var nodeImgs=
    {
        nodeOpened:
"images/treeImg/nodeOpened.gif",
        nodeOpener:
"images/treeImg/NodeOpener.gif",
        nodeOpening:
"images/treeImg/nodeOpening.gif",
        nodeNoChd:
"images/treeImg/ext.axd.gif",
        fopen:
"images/treeImg/fopen.gif",
        fclose:
"images/treeImg/fclose.gif",
        file:
"images/treeImg/l4.gif",
        nodeTopOpen:
"images/treeImg/node_top_1.gif",
        nodeTopClose:
"images/treeImg/node_top.gif",
        nodeMidOpen:
"images/treeImg/mnode.gif",
        nodeMidClose:
"images/treeImg/pnode.gif",
        nodeBotOpen:
"images/treeImg/plastnode_1.gif",
        nodeBotClose:
"images/treeImg/plastnode.gif",
        nodeVertLine:
'images/treeImg/vertline.gif',
        nodeThreeLine:
'images/treeImg/node.gif',
        nodeBlank:
'images/treeImg/blank.gif',
        nodeLastLine:
'images/treeImg/lastnode.gif',
        nodeLoading:
'images/treeImg/loading.gif'
    }; 
    
var setTimeWaiting;
    
function onGetTree(value,Node)
    {
        
if(Node.LoadingImg!=null)
        {
            
//容错处理,因为setTimeWaiting有200ms的延迟,如果在延迟时间里双击图标,不致出错,虽然这种情况很少出现(追求完美)
            Node.LoadingImg.src=nodeImgs.fopen;
            Node.LoadingImg.src1
=nodeImgs.fclose;
            Node.nodeStateImg.src
=nodeImgs.nodeOpened;
            Node.nodeStateImg.src1
=nodeImgs.nodeOpener;
            Node.style.display
="block";
       
        }
        
for(var i=0;i<value.length;i++)
        {
            
var ul = document.createElement("ul");
            ul.className
="Level_1";                                         
            
var li2 = document.createElement("li");
            li2.innerHTML
=value[i].MenuName;
            li2.className
='li_txt';
            
var li1 = document.createElement('li');
            
for(var j=0;j<value[i].MenuLevel;j++)
            {   
                
var img = $c("img");
                img.src
=nodeImgs.nodeBlank;
                li1.appendChild(img);
            }
            
if(value[i].ChildCount!=0) //如果还有子节点
            {
                
var img1 = document.createElement('img');
                img1.src
=nodeImgs.nodeOpener;
                img1.src1
=nodeImgs.nodeOpened;
                
                
var _id=value[i].MenuId;

                
var img2 = document.createElement('img');
                img2.src
=nodeImgs.fclose;
                img2.src1
=nodeImgs.fopen;
                
                img1.onclick
=(function(img1,img2,_id,ul){
                        
return function(){
                                
if(img2.src.indexOf(nodeImgs.nodeLoading)>0){return;}
                                
                                
var div = ul.nextSibling;
                                
if(div==null||div.nodeName.toLowerCase() !="div")
                                {
                                    
var div=document.createElement("div");
                                    div.style.display
="block";
                                    div.style.width
="110%";
                                    div.nodeStateImg
=img1;
                                    div.LoadingImg
=img2;
                                    div.setTimeWaiting
=setTimeout(function(){img2.src=nodeImgs.nodeLoading;},200);
                                    insertAfter(div,ul);
                                    BGMService.GetChildMenus(_id,
function(value){onGetTree(value,div);},onFailure);
                                }
                                
else
                                {
                                    switchAnttity(img1);
                                    switchAnttity(img2);
                                    
if(div.style.display=="block")
                                    {
                                        div.style.display
="none";
                                    }
                                    
else
                                    {
                                        div.style.display
="block";
                                    }
                                }
                }})(img1,img2,_id,ul);
                
                li2.onclick
=img1.onclick;
        
            }
            
else
            {
                
var img1 = document.createElement('img');
                
var img2 = document.createElement('img');
                img2.src
=nodeImgs.file;
                img1.src
=nodeImgs.nodeBlank;

                
var _src=value[i].Url;
                li2.onclick
=(function(text,_src){return function(){frame.addNewTab( text,text,_src);}})(value[i].MenuName,_src);
            }

            clearTimeout(Node.setTimeWaiting);
            
            li1.appendChild(img1);
            li1.appendChild(img2);
            
            ul.appendChild(li1);
            ul.appendChild(li2);
            
            Node.appendChild(ul);
        }
        
function switchAnttity(o)
        {
            
var temp=o.src;
            o.src
=o.src1;
            o.src1
=temp;
        }
    }
    
    
function onFailure(value)
    {
        alert(value.get_message());
    }
}

tree.prototype
={
    
    
    
}


 

 

  完整示例下载

 

 

 

 

 

 

 

 

 

 

posted @ 2010-12-31 11:40  vs_bug  阅读(2689)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3