天天看點

好大一棵樹,新春的祝福(二):功能節點的資料結構和頁面展示

目錄

          3、在權限方面的應用

     上一篇說了一下基本的n級分類的資料結構,最後提出了幾個缺點,但是卻沒有給出修改方法,是以呢現在繼續。

     1、資料結構

     在原有的基礎上,把noteID改成FunctionID,去掉code字段,增加三個字段。

     NoteLevel :表示第幾級的節點,可以和css配合,“美化”顯示效果。

     ParentIDPath: 父節點的路徑,用于找到一個節點的子節點和子子節點(及所有子節點)。也可以找到一個節點的所有父節點。

     OrderID :所有節點的總排序,大家一起來排序,一個SQL語句就可以提取出來直接綁定控件,而不需要在使用遞歸了。

     由于用功能節點作為例子,是以再增加兩個字段

     WebURL: 打開網頁的網址

     Target   : 打開網頁的目标

好大一棵樹,新春的祝福(二):功能節點的資料結構和頁面展示

【表結構的截圖】

     雖然使用三個字段才實作了原來的一個字段的功能,但是每個字段的分工都很明确,也更“專業”,當然你也可以說這三個都是備援字段。

     2、提取資料

     由于節點的縮進效果不用空格來占位了,是以這裡的提取資料的SQL就簡單很多了。

SELECT FunctionID, NoteTitle, NoteLevel, ParentIDPath, WebURL, Target FROM Test_Tree2 ORDER BY  OrderID

 【提取資料用的SQL語句】

     還是一條SQL語句,由于OrderID是所有節點的總排序,是以得到記錄集之後直接綁定控件就可以了,不需要使用遞歸。當然這裡說的控件不是TreeView,而是Repeater、GridView等。

好大一棵樹,新春的祝福(二):功能節點的資料結構和頁面展示

【使用OrderID字段排序的效果】

     3、如何來顯示?(請CSS來幫忙)

     為什麼放着好好的 TreeView 不用呢?因為他不是太靈活,不好控制頁面的顯示,如果美工做得效果太特殊了,那麼就不好弄了。

     對于“單列”的樹,我習慣使用Repeater來顯示,内部采用DIV。而對于“多列”的樹,我們可以使用GridView控件。GridView控件的樹狀結構在下一篇(權限選擇)裡面來說明。

     使用 Repeater 也是很簡單的。

 .aspx裡的代碼:

<asp:Repeater ID="Rpt" runat="server">

        <ItemTemplate>

            <div id='n<%# (Container.DataItem as DataRowView)["FunctionID"]%>'><%# (Container.DataItem as DataRowView)["noteTitle"]%></div>

        </ItemTemplate>

        </asp:Repeater>

.aspx.cs裡面的代碼:

好大一棵樹,新春的祝福(二):功能節點的資料結構和頁面展示

private void BindTree()

好大一棵樹,新春的祝福(二):功能節點的資料結構和頁面展示
好大一棵樹,新春的祝福(二):功能節點的資料結構和頁面展示
好大一棵樹,新春的祝福(二):功能節點的資料結構和頁面展示

{

好大一棵樹,新春的祝福(二):功能節點的資料結構和頁面展示

            //提取資料

好大一棵樹,新春的祝福(二):功能節點的資料結構和頁面展示

            string sql = "SELECT FunctionID, NoteTitle, NoteLevel, ParentIDPath, WebURL, Target FROM Test_Tree2 ORDER BY  OrderID";

好大一棵樹,新春的祝福(二):功能節點的資料結構和頁面展示

            DataTable dt = dal.RunSqlDataTable(sql);

好大一棵樹,新春的祝福(二):功能節點的資料結構和頁面展示
好大一棵樹,新春的祝福(二):功能節點的資料結構和頁面展示

            Rpt.DataSource = dt;

好大一棵樹,新春的祝福(二):功能節點的資料結構和頁面展示

            Rpt.DataBind();

好大一棵樹,新春的祝福(二):功能節點的資料結構和頁面展示
好大一棵樹,新春的祝福(二):功能節點的資料結構和頁面展示
好大一棵樹,新春的祝福(二):功能節點的資料結構和頁面展示

            輸出js腳本需要的js數組#region 輸出js腳本需要的js數組

好大一棵樹,新春的祝福(二):功能節點的資料結構和頁面展示

            if (dt.Rows.Count > 0)

好大一棵樹,新春的祝福(二):功能節點的資料結構和頁面展示
好大一棵樹,新春的祝福(二):功能節點的資料結構和頁面展示
好大一棵樹,新春的祝福(二):功能節點的資料結構和頁面展示
好大一棵樹,新春的祝福(二):功能節點的資料結構和頁面展示

                System.Text.StringBuilder str = new System.Text.StringBuilder();

好大一棵樹,新春的祝福(二):功能節點的資料結構和頁面展示
好大一棵樹,新春的祝福(二):功能節點的資料結構和頁面展示

                str.Append("<script language=\"javascript\">var notes = new Array();");

好大一棵樹,新春的祝福(二):功能節點的資料結構和頁面展示

                //打開指定結點的子結點 還未實作功能

好大一棵樹,新春的祝福(二):功能節點的資料結構和頁面展示

                str.Append("var firstID = " + dt.Rows[0][0].ToString() + " ;\r\n");

好大一棵樹,新春的祝福(二):功能節點的資料結構和頁面展示

                str.Append("var lastID = " + dt.Rows[dt.Rows.Count - 1][0].ToString() + " ;\r\n");

好大一棵樹,新春的祝福(二):功能節點的資料結構和頁面展示

                str.Append("var a = notes;\r\n");

好大一棵樹,新春的祝福(二):功能節點的資料結構和頁面展示

                foreach (DataRow dr in dt.Rows)

好大一棵樹,新春的祝福(二):功能節點的資料結構和頁面展示
好大一棵樹,新春的祝福(二):功能節點的資料結構和頁面展示
好大一棵樹,新春的祝福(二):功能節點的資料結構和頁面展示
好大一棵樹,新春的祝福(二):功能節點的資料結構和頁面展示

                    str.Append("a[");

好大一棵樹,新春的祝福(二):功能節點的資料結構和頁面展示

                    str.Append(dr["FunctionID"].ToString());            //FunctionID

好大一棵樹,新春的祝福(二):功能節點的資料結構和頁面展示

                    str.Append("] = new Array('");

好大一棵樹,新春的祝福(二):功能節點的資料結構和頁面展示

                    str.Append(dr["NoteLevel"].ToString());                //noteLevel

好大一棵樹,新春的祝福(二):功能節點的資料結構和頁面展示

                    str.Append("','");

好大一棵樹,新春的祝福(二):功能節點的資料結構和頁面展示

                    str.Append(dr["ParentIDPath"].ToString());                    //path

好大一棵樹,新春的祝福(二):功能節點的資料結構和頁面展示
好大一棵樹,新春的祝福(二):功能節點的資料結構和頁面展示

                    str.Append(dr["WebURL"].ToString());                //weburl

好大一棵樹,新春的祝福(二):功能節點的資料結構和頁面展示
好大一棵樹,新春的祝福(二):功能節點的資料結構和頁面展示

                    str.Append(dr["Target"].ToString());                //target

好大一棵樹,新春的祝福(二):功能節點的資料結構和頁面展示
好大一棵樹,新春的祝福(二):功能節點的資料結構和頁面展示

                    str.Append(dr["NoteLevel"].ToString() == "1" ? "1" : "0");                //isshow

好大一棵樹,新春的祝福(二):功能節點的資料結構和頁面展示

                     str.Append("')\r\n");

好大一棵樹,新春的祝福(二):功能節點的資料結構和頁面展示

                }

好大一棵樹,新春的祝福(二):功能節點的資料結構和頁面展示
好大一棵樹,新春的祝福(二):功能節點的資料結構和頁面展示

                str.Append("</script>");

好大一棵樹,新春的祝福(二):功能節點的資料結構和頁面展示
好大一棵樹,新春的祝福(二):功能節點的資料結構和頁面展示

                Response.Write(str.ToString());

好大一棵樹,新春的祝福(二):功能節點的資料結構和頁面展示

            }

好大一棵樹,新春的祝福(二):功能節點的資料結構和頁面展示

            #endregion

好大一棵樹,新春的祝福(二):功能節點的資料結構和頁面展示

        }

【Repeater的前台和背景的代碼】

     這樣倒是可以顯示出來,但是也太難看了,根本就區分不出來一級節點和二級節點,這樣拿出來還不得被罵s。别着急我們可以請css來“美化”一下。

     增加了class屬性和滑鼠跟随和滑鼠單擊的Repeater的代碼:

 <asp:Repeater ID="Rpt" runat="server">

            <div style="display:block" id='n<%# (Container.DataItem as DataRowView)["FunctionID"]%>' class='css_Tree<%# (Container.DataItem as DataRowView)["NoteLevel"]%>' onclick="treeClick(this)" onmouseover="treeOver(this)"  onmouseout="treeOut(this)">

            <%# (Container.DataItem as DataRowView)["noteTitle"]%></div>

    </div>

     CSS的代碼:

.css_Tree1  

    PADDING: 3px 1px 1px 10px ; 

    FONT-WEIGHT: bold; 

    FONT-SIZE: 16px; 

    COLOR: #222222;

    LINE-HEIGHT: 150%; 

    HEIGHT: 20px; 

    background-color:#ddddda; 

}

.css_Tree2  

    PADDING: 4px 1px 1px 30px ; 

    FONT-SIZE: 12px; 

    COLOR: #111111;  

    height:18pt; 

    background-color:#f6f6f6; 

.mySelectTree1

    border: 0px solid #369;

    background-color: #ddddff;

    color: #000; 

.mySelectTree2

    border: 1px solid #369;

    background-color: #FFFFCF;

    color: #111; 

     FONT-SIZE: 12px; height:18pt;

.myActiveTree2

    background-color: #CBDDEE;

【css的代碼】

好大一棵樹,新春的祝福(二):功能節點的資料結構和頁面展示

【效果截圖】(好像還是挺難看的)

     怎麼樣?這樣可以看得過去了吧。當然我是一點藝術細胞都沒有的人,弄出來的css也是很難看,不過沒關系,我們可以請專業人士來寫出來漂亮的css。

     優點:隻要是可以用css表現出來的效果都可以加在這個“樹”上面,而所需要做得隻是修改一下css檔案,而不用改代碼。

     4、如何展開收攏(js腳本)

     總算是好看了一點,但是現在任何效果都沒有哇,至少也得弄出來個展開收攏的效果呀。

     所謂的收攏嘛,其實就是讓子節點不可見,讓網頁裡的标簽不可見的話,可以使用style="display:none" 來做到,可見的話可以使用style="display:block"。

     我們可以給 div 加一個onclick事件,在事件裡面修改子節點的display的值。

     思路很簡單,代碼也很簡單。(代碼在上面)

     5、加上滑鼠跟随和選中的效果

     這個還是js腳本來實作,給div加上 onclick、onmouseover、 onmouseout 事件,然後在事件裡面修改div的Class就可以了。

好大一棵樹,新春的祝福(二):功能節點的資料結構和頁面展示
好大一棵樹,新春的祝福(二):功能節點的資料結構和頁面展示

Code

 var oldDiv_Over

        var oldDiv_Active

        var oldCss1 

        var oldCss2 

        var oldCss_Over

        function treeClick(me)

        {

            var id = me.id;

            id = id.substring(1);

            var path = me.path;

            //alert(notes[id][2]);

            if (notes[id][2] == "#")

            {

                //一級節點,展開、收攏子節點。

                if (notes[id][4] == "1")

                {

                    //隐藏子節點

                    ShowNote(id,0);

                    notes[id][4] = "0"

                else

                    //顯示子節點

                    ShowNote(id,1);

                    notes[id][4] = "1"

                }    

            else

                //二級節點,打開網頁

                var url = notes[id][2] + "?fid=" + notes[id][0] ;

                window.open(url ,notes[id][3]);

                if (oldDiv_Active)

                    oldDiv_Active.className = oldCss2 ;

                oldDiv_Active = me;

                oldCss2 = me.className;

                me.className = "myActiveTree2";

        function ShowNote(ParentID,isShow)

            for (i=1;i<=lastID;i++)

                if (notes[i])

                    if (notes[i][0] == "2" )

                    {

                        path = notes[i][1];

                        if (path.indexOf("0," + ParentID) == 0 )

                        {

                            if (isShow == "0")

                                document.getElementById("n" + i).style.display = "none";

                            else

                                document.getElementById("n" + i).style.display = "block";

                        }

                    }

                } 

        function treeOver(me)

            oldDiv_Over = me;

            oldCss_Over = me.className;

            if (oldDiv_Over != null && oldDiv_Active != oldDiv_Over)

                if (notes[id][0] == "1")

                    me.className = "mySelectTree1";

                else    

                    me.className = "mySelectTree2";

        function treeOut(me)

             if (oldDiv_Over != null && oldDiv_Active != oldDiv_Over)

                oldDiv_Over.className = oldCss_Over ;

     6、小結

     這個功能節點的資料結構是n級的,css樣式也可以是n級的,但是js腳本卻是按照兩級來編寫的,為什麼呢?因為我覺得功能節點這一塊,設定成兩級的是比較合理的,客戶看起來和操作起來都比較舒服,如果級數多了的話,有一點迷宮的感覺了。

     什麼?您說您的項目就是很複雜的,二級的不夠必須是三級的,那麼怎麼實作呢?有兩種方法:

     第一種是把一級節點放在上面作為導航;第二種是,把三級節點做成标簽的形式。

     如果您的項目三級節點也是不行的,必須是四級的,那麼也可以,就是把上面的兩種方法和在一起,一級的節點放在上面作為導航欄,二級、三級的“升一級”放在左面的功能節點裡,四級節點做成标簽的形式。

     什麼?四級的還不夠,那我也沒有什麼辦法了。

示範效果,可以單擊節點

樹狀結構的示範

基本的n級分類

加一個“編号”

我的樹

功能示範

新聞管理

員工管理