基于Metronic的Bootstrap开发框架经验总结(11)--页面菜单的几种呈现方式

在常规的后台管理系统或者前端界面中,一般都有一个导航菜单提供给用户,方便选择所需的内容。基于Metronic的Bootstrap开发框架,是整合了Metroinc样式,以及Boostrap组件模块的内容,因此菜单的效果自然也是和Bootstrap一脉相承的。基于经常使用的几种菜单样式,本文进行了相关的介绍和展示。

1、菜单展示的三种方式

菜单的展示可以做成各种各样的效果,本文只是针对性的介绍其中的三种,两种左侧竖放的菜单,一种是水平横放的菜单。
样式1:


菜单收缩后界面如下所示。

样式2:

样式3:
水平样式的菜单如下所示:

2、几种布局的组织方式

由于这几种布局方式,它们的框架布局页面(也就是Layout页面)内容有所不同,一般情况下我们可以把它分别定义为一种Layout页面,这样在实际使用的时候包含它即可。
我根据上面几种样式,分别定义了几个不同的Layout页面,如下所示



一般情况下,我们生成一个视图页面,会提示我们选择不同的视图布局页面的,确认之后会在页面顶部应用对应的Layout页面。



如果我们需要动态指定页面的布局内容,可以在上面使用一个变量来处理,如下代码所示。
@{ Layout = **ConfigData.ViewLayoutFile**;// "~/Views/Shared/_Layout.cshtml";  ViewBag.Title = "角色信息";}

实际上,我们一般的页面布局确定好后,就相对比较少变更的,所以为了不打破这个生成页面的布局内容,我们可以把前面处理好的Layout1/2/3等这些复制到Layout页面里面进行处理即可。
不过页面里面还是需要根据不同布局页面,指定不同的资源的。
我们添加样式的资源如下所示。

//开始全局必需样式引用
css_metronic.Include("~/Content/metronic/assets/global/plugins/font-awesome/css/font-awesome.min.css",
   "~/Content/metronic/assets/global/plugins/simple-line-icons/simple-line-icons.min.css",
   "~/Content/metronic/assets/global/plugins/bootstrap/css/bootstrap.min.css",
   "~/Content/metronic/assets/global/plugins/bootstrap-switch/css/bootstrap-switch.min.css",

  ..........................

   //主题全局样式
   "~/Content/metronic/assets/global/css/components-rounded.css",
   "~/Content/metronic/assets/global/css/plugins.min.css",
    //主题布局样式
   "~/Content/metronic/assets/layouts/" + Layout + "/css/layout.css",
   "~/Content/metronic/assets/layouts/" + Layout + "/css/themes/default.min.css",
   "~/Content/metronic/assets/layouts/" + Layout + "/css/custom.min.css"

   );

上面红色的Layout是我们根据不同布局页面获得的一个变量,从而能够使得不同布局页面的样式和脚本顺利引入的。

    /// <summary>
    /// 系统定义的一些常用变量
    /// </summary>
    public class ConfigData
    {
        /// <summary>
        /// Web开发框架所属的系统类型定义
        /// </summary>
        public const string SystemType = "WareMis";

        /// <summary>
        /// 配置视图的样式布局
        /// </summary>
        public static LayoutType Layout = LayoutType.Layout2;
    }

    /// <summary>
    /// 布局样式枚举
    /// </summary>
    public enum LayoutType
    {
        Layout,
        Layout2,
        Layout3
    }

3、菜单的动态生成

为了实现菜单动态的生成,我们需要了解这几种方式的菜单结构,然后我们根据它们的特点进行数据结构的生成即可。
第一第二种布局方式的菜单结构数据是一样的,它们的内容如下所示。

<ul class="page-sidebar-menu page-header-fixed " data-keep-expanded="false" data-auto-scroll="true" data-slide-speed="200">
    <li class="nav-item start" id="1">
        <a href="/Home/index?tid=1" class="nav-link nav-toggle">
            <i class="icon-home"></i>
            <span class="title">首页</span>
            <span class="selected"></span>
            <span class="arrow open"></span>
        </a>
    </li>
    @Html.Raw(@ViewBag.MenuString)
  </ul>

我们可以通过后台生成:@Html.Raw(@ViewBag.MenuString)
然后输出的界面里即可。
我们来看看前两种菜单的结构,简单的结构如下所示

<li class="nav-item start" id="1">
    <a href="/Home/index?tid=1" class="nav-link nav-toggle">
        <i class="icon-home"></i>
        <span class="title">首页</span>
        <span class="selected"></span>
        <span class="arrow open"></span>
    </a>
</li>

如果有子菜单的,那么两级菜单的结构如下所示。

<li class="nav-item " id="3">
    <a href="javascript:;" class="nav-link nav-toggle">
        <i class="icon-rocket"></i>
        <span class="title">客户管理</span>
        <span class="arrow"></span>
    </a>
    <ul class="sub-menu">
        <li class="nav-item " id="31">
            <a href="second?tid=3&sid=31">
                <i class="glyphicon glyphicon-th-list"></i>
                <span class="title">客户管理</span>
            </a>
        </li>
        <li class="nav-item  " id="32">
            <a href="second?tid=3&sid=32">
                <i class="icon-basket"></i>
                <span class="badge badge-roundless badge-danger">new</span>
                <span class="title">客户联系人</span>
            </a>
        </li>
    </ul>
</li>

如果是三级菜单的结构,如下所示:

<li class="nav-item active open" id="2">
    <a href="javascript:;" class="nav-link nav-toggle">
        <i class="icon-basket"></i>
        <span class="title">行业动态</span>
        <span class="selected"></span>
        <span class="arrow open"></span>
    </a>
    <ul class="sub-menu">
        <li class="nav-item  active open" id="21">
            <a href="javascript:;" class="nav-link nav-toggle">
                <i class="icon-home"></i>
                <span class="title">行业动态</span>
                <span class="arrow"></span>
                <span class="selected"></span>
            </a>
            <ul class="sub-menu">
                <li class="nav-item  active open" id="211">
                    <a href="second?tid=2&sid=21&ssid=211">
                        <i class="icon-home"></i>
                        <span class="badge badge-danger">4</span>
                        <span class="title">政策法规</span>
                    </a>
                </li>
                <li class="nav-item " id="212">
                    <a href="second?tid=2&sid=21&ssid=212">
                        <i class="icon-basket"></i>
                        <span class="badge badge-warning">4</span>
                        <span class="title">通知公告</span>
                    </a>
                </li>
            </ul>
        </li>
    </ul>
</li>

根据这些内容,我们在后台动态输出菜单结构即可。
例如我们在基类控制器里面,通过判断视图的处理,实现菜单内容的输出。

/// <summary>
/// 重载视图展示界面,方便放置一些常规的ViewBag变量。
/// 如果放在OnActionExecuting,则会导致任何请求都会执行一次,从而导致多次执行,降低响应效率
/// </summary>
protected override ViewResult View(string viewName, string masterName, object model)
{
    //登录信息统一设置
    if (CurrentUser != null)
    {
        ViewBag.FullName = CurrentUser.FullName;
        ViewBag.Name = CurrentUser.Name;

        //ViewBag.MenuString = GetMenuString();
        ViewBag.MenuString = GetMenuStringCache(); //使用缓存,隔一段时间更新
    }

    return base.View(viewName, masterName, model);
}

为了提高菜单的响应处理,避免多次递归耗时,我们可以把生成好的菜单内容,放到缓存里面,通过键值实现处理。

/// <summary>
/// 使用分布式缓存实现菜单数据的缓存处理
/// </summary>
/// <returns></returns>
public string GetMenuStringCache()
{
    string itemValue = MemoryCacheHelper.GetCacheItem<string>("GetMenuStringCache_" + CurrentUser.ID , delegate()
        {
            return GetMenuString();
        },
        null, DateTime.Now.AddMinutes(5) //5分钟以后过期,重新获取
    );
    return itemValue;
}

而对于水平方向的菜单处理,和前面两者有所不同。



如二级菜单数据展示如下所示。

<li class="menu-dropdown classic-menu-dropdown ">
    <a href="index.html" class="nav-link  ">
        <i class="icon-bar-chart"></i> Default
        <span class="arrow"></span>
    </a>
</li>
<li class="menu-dropdown classic-menu-dropdown active">
    <a href="javascript:;" class="nav-link nav-toggle ">
        <i class="icon-basket"></i> Dashboard
        <span class="arrow"></span>
    </a>
    <ul class="dropdown-menu pull-left">
        <li class=" active">
            <a href="index.html" class="nav-link  active">
                <i class="icon-bar-chart"></i>Dashboard
                <span class="arrow"></span>
            </a>
        </li>
    </ul>
</li>

三级菜单展示的数据如下所示。

<li class="menu-dropdown classic-menu-dropdown ">
    <a href="javascript:;" class="nav-link nav-toggle ">
        <i class="icon-briefcase"></i> Pages
        <span class="arrow"></span>
    </a>
    <ul class="dropdown-menu pull-left">
        <li class="dropdown-submenu ">
            <a href="javascript:;" class="nav-link nav-toggle ">
                <i class="icon-basket"></i> eCommerce
                <span class="arrow"></span>
            </a>
            <ul class="dropdown-menu">
                <li class=" ">
                    <a href="ecommerce_index.html" class="nav-link ">
                        <i class="icon-home"></i> Dashboard
                    </a>
                </li>
                <li class=" ">
                    <a href="ecommerce_orders.html" class="nav-link ">
                        <i class="icon-basket"></i> Orders
                    </a>
                </li>
            </ul>
        </li>

        <li class="dropdown-submenu">
            <a href="javascript:;" class="nav-link nav-toggle">
                <i class="icon-notebook"></i> Login
                <span class="arrow"></span>
            </a>
            <ul class="dropdown-menu pull-left">
                <li class="">
                    <a href="page_user_login_1.html" class="nav-link " target="_blank"> Login Page 1 </a>
                </li>
                <li class="">
                    <a href="page_user_login_2.html" class="nav-link " target="_blank"> Login Page 2 </a>
                </li>
            </ul>
        </li>
    </ul>
</li>

我们所需要做的就是把我们数据库里面的菜单数据,动态构建这种递进式的数据结构即可。


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343

推荐阅读更多精彩内容