上篇文章我们完成了 动态生成多级菜单 这个实用组件。

本篇文章我们要开发另一个实用组件:面包屑导航。

面包屑导航(BreadcrumbNavigation)这个概念来自童话故事"汉赛尔和格莱特",当汉赛尔和格莱特穿过森林时,不小心迷路了,但是他们发现在沿途走过的地方都撒下了面包屑,让这些面包屑来帮助他们找到回家的路。所以,面包屑导航的作用是告诉访问者他们目前在网站中的位置以及如何返回。(摘自百度百科)

要实现面包屑导航,也可以直接从nuget搜一些sitemap组件直接使用。

当然,和上篇一样,我们同样不用任何第三方组件,完全自己构建灵活通用的sitemap.

下面给出我的最佳实践。

文章提纲

  • 概述要点
  • 详细步骤

    一、分析多级目录的html结构

    二、根据html结构构建xml的站点地图源及相应的data model

   三、构建html helper, 完成breadcrumb生成功能

   四、前端调用

  • 总结

概述要点

实现面包屑导航分成两个步骤:

1. 获取当前的url地址,根据url地址去相关配置文件中查询到当前位置,递归查询父节点

2. 根据查询到的结果动态拼接出 breadcrumb 的html

如果大家看了上篇文章应该会对这篇文章用到的技术很熟悉(比上篇文章更简单 : ))

我们直接根据站点的配置拼接出 html,前端通过自定义html helper的方法调用获取拼接出的内容。

关于如何自定义html helper,上篇文章有介绍,不再重复。

下面直接讲解详细步骤。

详细步骤

分成四个步骤

一、分析多级目录的html结构

首先打开一个样例,如下图

对应的html为

大家可以看到,由两层组成, 外面是一个<ol>, 里面是一组<li>。

每个<li>包含一个<a>标签,指向相应的位置地址。

最后的<li>不包含<a>标签,仅显示名字。

二、根据html结构构建xml的站点地图源及相应的data model

1. 根据上面的html结构,我们准备站点地图的数据源。

一般来说,站点地图不涉及到权限,也不会经常改变,如网站的某个位置没有配置,直接不显示即可,也不会有其他影响。

因此我们简单起见,直接准备个xml文档即可。

<?xml version="1.0" encoding="utf-8" ?>

<!--填绝对路径,类似 /XEngine/home/about-->

<MvcSiteMaps>

<MvcSiteMap ParnetID = "0" Name = "主页" Url = "/XEngine/" ID = "1" ></MvcSiteMap>

<MvcSiteMap ParnetID = "1" Name = "组织" Url = "/XEngine/Organization" ID = "2"></MvcSiteMap>

<MvcSiteMap ParnetID = "2" Name = "关于" Url = "/XEngine/home/about" ID = "3"></MvcSiteMap>

</MvcSiteMaps>

最终我们只需要将xml中相应的值填充到breadcrumb的html

2. 准备对应的data model

[XmlRoot("MvcSiteMaps")]

public class MvcSiteMaps

{

[XmlElement("MvcSiteMap")]

public MvcSiteMap[] Items { get; set; }

}

public class MvcSiteMap

{

[XmlAttribute(AttributeName = "ID")]

public int ID { get; set; }

[XmlAttribute(AttributeName = "Name")]

public string Name { get; set; }

[XmlAttribute(AttributeName = "Url")]

public string Url { get; set; }

[XmlAttribute(AttributeName = "ParnetID")]

public int ParnetID { get; set; }

public MvcSiteMap Parent { get; set; }

}

注意 [XmlAttribute(AttributeName = "xxx")],AttributeName需要和xml里面的名字对应,我们的xml和data model的命名完全对应,所以也可以省略。

三、构建html helper, 完成breadcrumb生成功能

需要完成以下几个功能

1. 获取xml中所有的节点信息

private static string SiteMapString = System.Configuration.ConfigurationManager.AppSettings["SiteMapString"] ?? string.Empty;

//获取sitemap的配置信息

public static IList<MvcSiteMap> GetSiteMapList()

{

using (TextReader reader = new StreamReader(HttpContext.Current.Server.MapPath(SiteMapString)))

{

var serializer = new XmlSerializer(typeof(MvcSiteMaps));

var items = (MvcSiteMaps)serializer.Deserialize(reader);

if (items != null)

{

return items.Items;

}

return null;

}

}

2. 根据上一步获取的节点信息及当前url地址,拼接出面包屑html

/// <summary>

/// 填充面包屑

/// </summary>

/// <param name="url"></param>

/// <returns></returns>

public static MvcHtmlString PopulateBreadcrumb(string url)

{

StringBuilder str = new StringBuilder();

List<string> pathList = new List<string>();

MvcSiteMap current = GetSiteMapList().FirstOrDefault(m=>m.Url==url);

GetParent(current, pathList);

pathList.Reverse();

for (int i = 0; i < pathList.Count; i++)

{

if (i == pathList.Count - 1)

{

string s = pathList[i];

s = s.Substring(s.IndexOf(">") + 1, s.LastIndexOf("<") - s.IndexOf(">") - 1);

str.AppendFormat("<li class='active'>{0}</li>", s);

}

else

{

str.AppendFormat("<li>{0}</li>", pathList[i]);

}

}

string result = str.ToString();

return MvcHtmlString.Create(result);

}

说明:首先找到当前位置,递归找出父节点依次添加到列表中;反转列表,完善html代码。

/// <summary>

/// 递归找到上一级

/// </summary>

/// <param name="parent"></param>

/// <param name="pathList"></param>

static void GetParent(MvcSiteMap parent, List<string> pathList)

{

if (parent != null)

{

pathList.Add(string.Format("<a href={0}>{1}</a>", parent.Url, parent.Name));

parent.Parent = GetSiteMapList().FirstOrDefault(i => i.ID == parent.ParnetID);

GetParent(parent.Parent, pathList);

}

}

四、前端调用

类似于上一篇文章,我们新建个html helper供前端调用。

这次我们稍微做一点改进(规范一下命名)

先看下微软原生的html helper定义方法,以Html.ActionLink为例,如下图

如方框处,类似于 xxxExtensions的命名,我们定义一个静态类来调用之前的方法。

前端调用:

以访问http://localhost/XEngine/home/about 为例,最终返回的结果

相应的html为:

<div>

<br />

<ol class="breadcrumb">

<li><a href=/XEngine/>主页</a></li><li><a href=/XEngine/Organization>组织</a></li><li class='active'>关于</li>

</ol>

</div>

总结

本篇对上篇的用到的html helper知识点做了细微改进 :

规范了自定义 html helper命名(类名为xxxExtensions和,原生形式统一);

直接返回MvcHtmlString类型,这样html字符串不会被转义,可以直接在前端调用。

自定义的 html helper非常实用,大家可以多多挖掘使用场景。

欢迎大家多多评论,祝学习进步:)

P.S.

示例中前端直接在_Layout.cshtml中使用。

后端菜单相关的程序结构:

MVC 5 + EF6 入门完整教程14 -- 动态生成面包屑导航的更多相关文章

  1. MVC5+EF6 入门完整教程13 -- 动态生成多级菜单

    稍微有一定复杂性的系统,多级菜单都是一个必备组件. 本篇专题讲述如何生成动态多级菜单的通用做法. 我们不用任何第三方的组件,完全自己构建灵活通用的多级菜单. 需要达成的效果:容易复用,可以根据mode ...

  2. MVC5 + EF6 入门完整教程1

    https://www.cnblogs.com/miro/p/4030622.html 第0课 从0开始 ASP.NET MVC开发模式和传统的WebForm开发模式相比,增加了很多"约定& ...

  3. MVC5 + EF6 入门完整教程二

    从前端的UI开始 MVC分离的比较好,开发顺序没有特别要求,先开发哪一部分都可以,这次我们主要讲解前端UI的部分. ASP.NET MVC抛弃了WebForm的一些特有的习惯,例如服务器端控件,Vie ...

  4. MVC5+EF6 入门完整教程11--细说MVC中仓储模式的应用

    摘要: 第一阶段1~10篇已经覆盖了MVC开发必要的基本知识. 第二阶段11-20篇将会侧重于专题的讲解,一篇文章解决一个实际问题. 根据园友的反馈, 本篇文章将会先对呼声最高的仓储模式进行讲解. 文 ...

  5. MVC5+EF6 入门完整教程12--灵活控制Action权限

    大家久等了. 本篇专题主要讲述MVC中的权限方案. 权限控制是每个系统都必须解决的问题,也是园子里讨论最多的专题之一. 前面的系列文章中我们用到了 SysUser, SysRole, SysUserR ...

  6. MVC5+EF6 入门完整教程

    MVC5+EF6 入门完整教程11--细说MVC中仓储模式的应用 MVC5+EF6 入门完整教程10:多对多关联表更新&使用原生SQL@20150521 MVC5+EF6 入门完整教程9:多表 ...

  7. MVC5+EF6 入门完整教程九

    前一阵子临时有事,这篇文章发布间隔比较长,我们先回顾下之前的内容,每篇文章用一句话总结重点. 文章一 MVC核心概念简介,一个基本MVC项目结构 文章二 通过开发一个最基本的登录界面,介绍了如何从Co ...

  8. MVC5 + EF6 入门完整教程(转载)--01

    MVC5 + EF6 入门完整教程   第0课 从0开始 ASP.NET MVC开发模式和传统的WebForm开发模式相比,增加了很多"约定". 直接讲这些 "约定&qu ...

  9. MVC5+EF6 入门完整教程 总目录

    本系列文章会从一个主干开始,逐渐深入,初步规划30篇.初级10篇,中级10篇,综合项目实战10篇 初级10篇 MVC5+EF6 入门完整教程10:多对多关联表更新&使用原生SQL@201505 ...

随机推荐

  1. 在线制作h5——上帝的礼物

    在线制作h5 网址:http://www.godgiftgame.com 网站名称:上帝的礼物 推荐指数:5颗星 功能概要 可以设置背景.元素图片.元素文字.元素图形.声音.加载.链接.分享,生成h5 ...

  2. Solved: Qt Library LNK 2001 staticMetaObject error

          在链接Qt的库,比如QtGui4.lib,我这里是在链接QtSolutions_PropertyBrowser-head.lib的时候出现的链接错误.大概是说一个"XXXX::s ...

  3. 云计算的三层SPI模型

    (转自:http://hi.baidu.com/fengjun8216/item/b15bbef4dcf74049922af27b) 一般而言,云计算架构可以用三层SPI模型来表述. 一.基础设施即服 ...

  4. JAVA SE 803 考试前突击

    考试的宗旨仍然是掌握基础知识,不过鉴于Oracle的这个认证考试还有不少的大家来找茬的成份在,所以一定一定要细心为上.   关于抽象类的坑点集合: 抽象类不是必须得有抽象方法,但有抽象方法的类必须是抽 ...

  5. 【总结】编写自己的JDBC框架

    一.数据库连接池: 在一般用JDBC 进行连接数据库进行CRUD操作时,每一次都会: 通过:java.sql.Connection conn = DriverManager.getConnection ...

  6. 使用BAT批处理执行sql语句的代码

    使用BAT批处理执行sql语句的代码 有时候需要执行一些Sql语句时,不想开企业管理器,或者是发给客户执行但那边又不懂代码,这时就可以用下面方法 1.把待执行Sql保存在一个文件,这里为2011022 ...

  7. 刨根问底U3D---从Profile中窥探Unity的内存管理

    这篇文章包含哪些内容 这篇文章从Unity的Profile组件入手,来探讨一下Unity在开发环境和正式环境中的内存使用发面的一些区别, 并且给出了最好控制内存的方法(我想你已经知道了...Prefa ...

  8. [leetode]Binary Search Tree Iterator

    用个stack模拟递归即可 /** * Definition for binary tree * struct TreeNode { * int val; * TreeNode *left; * Tr ...

  9. windows内核结构

  10. Microsoft 2013 新技术学习笔记 二

    在探讨系统重构的代码结构组织之前,先初步考虑框架与数据库的交互,在.net平台上数据访问方案有人总结为三类:DataSet.ADO.net 2.0.ORM组件.我只熟悉ADO.NET方式,众多的企业特 ...