上篇文章我們完成了 動態生成多級選單 這個實用元件。
本篇文章我們要開發另一個實用元件:麵包屑導航。
麵包屑導航(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中使用。
後端選單相關的程式結構: