zoukankan      html  css  js  c++  java
  • Mvc Tree的简单应用

    最近我们的项目中需要用到树型菜单,以前使用WebForm时,树型菜单有微软提供的控件,非常方便,但现在需要在asp.netmvc中使用树形菜单,先说明下我们对树形菜单的需求:
          1:需要支持CheckBox,允许对菜单项进行选择;
          2:当选择父菜单时,它下面的子菜单全部选中;
          3:当取消父菜单的选中状态时,下面的子菜单也全部取消;
          4:要比较方便的与MVC结合。
         
          初步思路:
          思路一:jquery相关的树形菜单插件,由于项目中有应用到jquery,所以不考虑采用其它js框架的产品。
          思路二:asp.net mvc相应的控件,这里指的控制就好比分页控件之类,基本思路就是扩展HtmlHelper来实现,Html逻辑一般都封闭在dll中。
         
          经过一轮筛选后的结果:
         
          思路一:基于js的树形菜单果然有很多,最终我选择了https://github.com/daredevel/jquery-tree,从demo展示来看,它完全能够满足我上面提到的前三个需求。
          思路二:Telerik也有相应的树形菜单控件,它能够很好的结合MVC,最大特点是将View上的树形菜单数据传递给Controller很直观。
         
          最终方案:


          由于上面的两个产品不能完全符合我的要求,所以结合jquery-tree以及Telerik treeview设计理念来实现自己的树形菜单是最佳选择。
          jquery-tree本身只是一个基于前端的菜单,我们要想传递数据给Controller,唯一比较方便的方法就是通过ajax,但这需要开发人员有比较强的js操纵能力。
          Telerik treeview,有点杀鸡用牛刀的意思,Telerik提供了一整UI解决方案,如果我们只用其中的一个功能就引入它,有些不适时宜,但我非常喜欢它给出的思路,它能很好的将View的菜单数据传递给Controller,但Telerik由于提供的是控件,我们不太方便对它的样式做修改,我们更希望能够自由的控制UI显示逻辑。
         
           题外话:关于数据结构
           记的有一年,我去一家公司面试,当时估计是技术人员都不在,所以安排了一位年龄上比较大的面试官来面试我,目测应该是位级别不低的领导,当时不免有点小紧张。经过一番自我介绍以及工作经验介绍后,他现场给我出了一道题:
           写一个程序,打印出公司的组织结构图,比如最上层是CEO,下面是VP......
         
          我当时跟很大一部分.net程序员一样,做过几年项目后,什么数据结构啊,算法呀早就不记得了,那一刻只想到这是和树相关的数据结构,但不知为何,只想到了二叉树,心想总算想到了,于是开始定义二叉树数据结构,采用递归遍历数据,总之脑袋一片空白,写了一会,领导见我还没写完,有些不耐烦了,问我写完吗,我回答说还差一点,他等了一会见我还没写完,就说先给我看看,于时直接过来拿走我未写完的代码,我是多么的想争取那次机会呀,当时多么的舍不得交出去,最后的结果可想而知。
         
          并不是面试官问的问题有多么难,他考的问题只不过是计算机最基础的东西,而我正好忘记了。到现在我也面试过一些候选人,我也比较注意候选人的基础知识,其实说实在的,像做一些.net相关的企业级开发,大部分情况下我们是不会用到复杂数据结构的,算法就更不用说了,只有少数人会用到这些高级的东西。但这些数据结构以及算法知识会让你的视野更加开阔,在特定情况下能够给你一些方向,如果你对那块领域没有接触过,你是不会朝那方面想的。

          这次的树形菜单正好能够解答我以前那位面试官的问题。
         
          树形菜单数据结构:
          首先它属于树形数据结构,但不能定义成二叉树,因为一个总裁下面不可能只有两个副总,一个经理下面也不可能只有两个员工,下属应该是大于等于0的数据。
          下面是我定义的菜单数据对象:
      

    复制代码
    public class MyTreeViewItem
        {
            public IList<MyTreeViewItem> Items { get; set; }
            public string Value { get; set; }
            public bool Checked { get; set; }
            public string Text { get; set; }
            public string Index { get; set; }
            public MyTreeViewItem Parent { get; set; }
            public string HtmlDomName { get; set; }
        }
    复制代码

         
           字段说明:
           Text:用于显示的文本,比如:总裁
           Value:显示文本对应的ID,比如:0
           Index:这个是结合表单的辅助属性,View上使用
           Checked:当前菜单项是否被选中,用户提交表单后我们可以通过这个属性判断用户的选择项
           Items:当前菜单下的子菜单集合
           Parent:当前菜单的上级菜单
           HtmlDomName:这个是结合表单的辅助属性,View上使用
          
           树形菜单的输出:
           我上次面试过程中的递归逻辑还是有用的,这里我们仍然采用递归来输出菜单项。我创建了一个Partial View

    复制代码
    @model MvcTreeView.Controllers.MyTreeViewItem
    <ul>
        <li>
            @if (null == Model.Parent)
            {
                Model.HtmlDomName = "TreeView1_checkedNodes[" + Model.Index + "]";
            }
            else
            {
                Model.HtmlDomName = Model.Parent.HtmlDomName + ".Items[" + Model.Index + "]";
            }
            <input name='@(Model.HtmlDomName + ".Checked")' type="checkbox" onchange='setValue(this)'  value='False' />
            <input  name='@(Model.HtmlDomName + ".Text")' type="hidden" value="@Model.Text" />
            <input  name='@(Model.HtmlDomName + ".Index")' type="hidden" value="@Model.Index" />
            <span>@Model.Text</span>
            <input  name='@(Model.HtmlDomName + ".Value")' type="hidden"
                                            value="@Model.Value" />
            @if (null != Model.Items)
            {
                for (var i = 0; i < Model.Items.Count; i++)
                {
                @Html.Partial("NodeItem", Model.Items[i])
                }
            }
        </li>
    </ul>
    复制代码

       

           View向Controller的数据传递:

           无论是ajax还是直接post表单,最终的目的都是接收View中的数据,要想传递比较复杂的数据类型,我们需要对ASP.NET MVC Model Binding 有一定了解,之前也讲解过MyTreeViewItem的结果,有普通的数据类型,比如 string,bool,也是对象类型,比如MyTreeViewItem类型的Parent,也是基于集合的属性IList<MyTreeViewItem>,要想让表单中的数据直接传递给Controller,我们需要对表单元素的name进行特殊处理才行。如果大家对这部分不太理解,这篇文章可以参考:Understanding-ASP-NET-MVC-Model-Binding
         
           比如我是这样定义Model的:
        

    public class AboutModel
        {
            public MyTreeViewItem NodeItem { get; set; }

        }



           View:这是主要是加载菜单,至于如何使用jquery-tree,这里就不多说了,大家下可以自己下载demo。 
        

    复制代码
    @using (Html.BeginForm())
    {
        <div id="accordion">
            <h3>
                <a href="#">All components in default behaviour</a></h3>
            <div id="example-0">
                <div>
                 @if (null != Model.NodeItem)
                {
                    @Html.Partial("NodeItem", Model.NodeItem)
                }
                 
                </div>
            </div>
        </div>
        <input type="submit" id="example-0-button" />
    }
    复制代码

      

         Controller:这是最重要的就是接收参数,它是一个List类型,无论菜单项有多少层,都会按树形数据结构层次组织好,方便我们查询。
        

    [AcceptVerbs(HttpVerbs.Post)]
            public ActionResult About(List<MyTreeViewItem> TreeView1_checkedNodes)
            {
                return View(this.GetAboutModel());
            }

     
            UI效果图:下图也是我上次没有回答出来的面试题答案效果图。

            

            下图是Controller接收到的参数:

       

  • 相关阅读:
    HTML5结构
    HTML5新增的非主体元素header元素、footer元素、hgroup元素、adress元素
    CF GYM 100703G Game of numbers
    CF GYM 100703I Endeavor for perfection
    CF GYM 100703K Word order
    CF GYM 100703L Many questions
    CF GYM 100703M It's complicate
    HDU 5313 Bipartite Graph
    CF 560e Gerald and Giant Chess
    POJ 2479 Maximum sum
  • 原文地址:https://www.cnblogs.com/guoyu8/p/9834691.html
Copyright © 2011-2022 走看看