前言 童鞋們,大家好 我是專註.NET開發者社區建設的實踐者Rector。 首先,為自己間隔了兩個星期五再更新本系列文章找個不充分的理由:Rector最近工作,家庭的各種事務所致,希望大家諒解。 本文知識要點 回到本文的主題,還是關於系列文章:《一步一步創建ASP.NET MVC5程式Reposit ...
前言
童鞋們,大家好
我是專註.NET開發者社區建設的實踐者Rector。
首先,為自己間隔了兩個星期五再更新本系列文章找個不充分的理由:Rector最近工作,家庭的各種事務所致,希望大家諒解。
本文知識要點
回到本文的主題,還是關於系列文章:《一步一步創建ASP.NET MVC5程式Repository+Autofac+Automapper+SqlSugar》,本文將為大家分享的主要內容有:
- 響應式網站首頁的佈局與製作
- 文章列表的展示
- 文章詳情頁面
前端佈局與製作
響應式網站首頁的佈局與製作
在以本文之前的系列文章的頁面中,我們的網站首頁以及文章列表頁面都沒有應用樣式,本文將給大家分享首頁的製作,其中包含的內容有:
- 頭部導航
- 文章列表
- Bootstrap響應式佈局
最終的首頁效果圖如下:
CSS樣式
首先,在項目[TsBlog.Frontend]中創建資源文件夾命名為:resources,在其中創建一個css樣式文件夾,並新建一個樣式文件,命名為:site.css,此時的目錄結構如下:
樣式代碼如下:
site.css
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, font, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td { border: 0; margin: 0; padding: 0; }
body { color: #333; font-size: 14px; font-family: -apple-system,'helvetica neue', helvetica,"Helvetica Neue",Helvetica,Arial,"PingFang SC","Hiragino Sans GB","WenQuanYi Micro Hei","Microsoft Yahei",sans-serif; line-height: 22px; width: 100%; height: 100%; }
h1, h2, h3, h4, h5, h6 { clear: both; font-weight: normal; }
ol, ul { list-style: none; }
blockquote { quotes: none; border-left: 5px solid #eee; font-size: 14px; margin: 10px 0; padding: 10px 20px; }
blockquote:before, blockquote:after { content: ''; content: none; }
a { color: #4484ce; }
/*bootstrap override*/
.btn { border-radius: 2px !important; }
.btn-primary { background-color: #4484CE !important; }
.btn-primary:hover { background-color: #3A77BE !important; }
.navbar-nav a { color: #333 !important; }
.navbar-nav > .active > a, .navbar-nav > .active > a:focus, .navbar-nav > .active > a:hover, .navbar-nav a:hover { border-radius: 2px; background-color: #e7e7e7 !important; }
/*site begin*/
.ts-navbar .navbar-nav { height: 50px; vertical-align: middle; line-height: 50px; }
.ts-navbar .navbar-nav li { vertical-align: middle; line-height: 50px; float: none; display: inline-block; }
.ts-navbar .dropdown li { display: block; }
.ts-navbar .navbar-nav li a { padding: 8px 15px; }
.navbar-brand { height: auto; }
a.nav-btn-login { color: #fff !important; }
a.nav-btn-login:hover { background-color: #3A77BE !important; color: #fff !important; }
.navbar-profile { margin-right: 0; }
/*home begin*/
.jumbotron h1 { margin-bottom: 15px; }
.jumbotron p { line-height: 28px; }
.post-title { display: block; font-size: 16px; font-weight: 600; border-bottom: 2px solid #e7e7e7; padding-bottom: 8px; }
.post-item-box { margin-bottom: 15px; }
.post-item-box li { margin-top: 15px; margin-bottom: 15px; padding-top: 10px; padding-bottom: 10px; }
.post-item-box li h2 { font-size: 16px; font-weight: 500; margin-bottom: 10px; }
.post-item-summary { color: #555; }
.footer-box { padding: 15px; margin-top: 15px; border-top: 1px solid #e7e7e7; }
/*post details*/
.article-content { padding-top: 15px; padding-bottom: 15px; }
.article-content p { margin-top: 20px; margin-bottom: 20px; }
.article-fixed p { margin-top: 0; margin-bottom: 5px; }
.article-content h1, .article-content h2, .article-content h3, .article-content h4, .article-content h5, .article-content h6 { margin: 15px 0 10px; }
.article-content h1, .article-content h2 { border-bottom: 1px solid #eee; padding-bottom: 10px; }
.article-content h2 { font-size: 1.75em; line-height: 1.2 }
.article-content h3 { font-size: 1.5em; line-height: 1.2 }
.article-content blockquote { background: #f6f6f6 none repeat scroll 0 0; border-left: 2px solid #009a61; color: #555; font-size: 1em; }
.cloud-tags .cloud-tag-item { border: 1px solid #efefef; background-color: #f7f7f7; padding: 5px 10px; }
.cloud-tags .cloud-tag-item, .side-bar-article-list, .article-content { word-break: break-all; word-wrap: break-word; white-space: normal; }
.article-content pre { background-attachment: scroll; background-clip: border-box; background-color: #f6f6f6; border: medium none; line-height: 1.45; max-height: 35em; overflow: auto; padding: 1em; position: relative; margin-bottom: 15px; margin-top: 15px; }
.article-content ul li { padding-left: 15px; list-style: inside; }
.article-content ul li { padding-left: 15px; list-style: inside; }
.article-content ul, .article-content ol { margin-left: 3em; padding-left: 0; }
.article-content ul li, .article-content ol li { margin: .3em 0; }
以上的樣式表是本文中所用到的,你只需要複製即可。
頭部導航
打開視圖文件[...TsBlog\src\Presentation\TsBlog.Frontend\Views\Home\Index.cshtml],首先製作頭部導航條,其中導航條的HTML代碼如下:
<nav class="navbar navbar-default navbar-static-top ts-navbar">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="~/">TSBLOG</a>
</div>
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li class="active"><a href="~/">網站首頁</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">分類導航 <span class="caret"></span></a>
<ul class="dropdown-menu">
<li class="dropdown-header">後端開發</li>
<li><a href="http://2sharings.com/category/csharp-development">C#程式設計</a></li>
<li><a href="http://2sharings.com/category/dot-net">.NET程式設計</a></li>
<li><a href="http://2sharings.com/category/asp-dot-net">ASP.NET</a></li>
<li><a href="http://2sharings.com/category/asp-net-mvc">ASP.NET MVC</a></li>
<li><a href="http://2sharings.com/category/asp-dotnet-core">ASP.NET Core</a></li>
<li><a href="http://2sharings.com/category/winform">Winform</a></li>
<li role="separator" class="divider"></li>
<li class="dropdown-header">資料庫</li>
<li><a href="http://2sharings.com/category/mysql">MySQL</a></li>
<li><a href="http://2sharings.com/category/sql-server">SQL Server</a></li>
<li><a href="http://2sharings.com/category/sqlite">SqLite</a></li>
</ul>
</li>
<li><a href="~/home/about">關於我們</a></li>
<li><a href="~/home/contact">聯繫我們</a></li>
</ul>
<ul class="nav navbar-nav navbar-right navbar-profile">
<li><a href="~/account/register">免費註冊</a></li>
<li><a class="btn btn-primary nav-btn-login" href="~/account/login">立即登錄</a></li>
</ul>
</div><!--/.nav-collapse -->
</div>
</nav>
正文HTML
其中正文的第一部分為一個BANNER,在這個區域中,可以放置一些重要的關於站點的描述信息,也可以放滾動播放的廣告圖片等,按自己的需要處理就可以了。
第二部分則是一個文章列表區域,其中列出了網站最近發佈的20條文章列表,正文的HTML代碼如下:
<div class="container">
<div class="jumbotron">
<h1>小伙伴,你好</h1>
<p>歡迎來到 Rector 的ASP.NET MVC 5 系列文章教程。在這裡,Rector將和你一起一步一步創建一個集成Repository+Autofac+Automapper+SqlSugar的WEB應用程式。</p>
<p>你準備好了嗎?</p>
<p>......</p>
<p>讓我們開始ASP.NET MVC 5 應用程式的探索之旅吧!!!</p>
</div>
<strong class="post-title">文章列表(@(Model.Count())篇)</strong>
<ul class="list-unstyled post-item-box">
@foreach (var p in Model)
{
<li>
<h2><a href="~/post/details/@p.Id">@p.Title</a></h2>
<p class="post-item-summary">@p.Summary ... <a href="~/post/details/@p.Id">閱讀全文</a></p>
</li>
}
</ul>
</div>
頁腳
頁面最後為頁腳部分,包含比較簡單的版權等信息,HTML代碼如下:
<footer class="footer-box">
<div class="container">
版權所有 © @(DateTime.Now.Year)
</div>
</footer>
首頁完整的HTML代碼如下:
Index.cshtml
@model IEnumerable<TsBlog.ViewModel.Post.PostViewModel>
@{
Layout = null;
}
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>ASP.NET MVC 5 系列文章教程--首頁 | TSBLOG</title>
<link href="~/Content/bootstrap.min.css" rel="stylesheet" />
<link href="~/resources/css/site.css" rel="stylesheet" />
</head>
<body>
<nav class="navbar navbar-default navbar-static-top ts-navbar">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="~/">TSBLOG</a>
</div>
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li class="active"><a href="~/">網站首頁</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">分類導航 <span class="caret"></span></a>
<ul class="dropdown-menu">
<li class="dropdown-header">後端開發</li>
<li><a href="http://2sharings.com/category/csharp-development">C#程式設計</a></li>
<li><a href="http://2sharings.com/category/dot-net">.NET程式設計</a></li>
<li><a href="http://2sharings.com/category/asp-dot-net">ASP.NET</a></li>
<li><a href="http://2sharings.com/category/asp-net-mvc">ASP.NET MVC</a></li>
<li><a href="http://2sharings.com/category/asp-dotnet-core">ASP.NET Core</a></li>
<li><a href="http://2sharings.com/category/winform">Winform</a></li>
<li role="separator" class="divider"></li>
<li class="dropdown-header">資料庫</li>
<li><a href="http://2sharings.com/category/mysql">MySQL</a></li>
<li><a href="http://2sharings.com/category/sql-server">SQL Server</a></li>
<li><a href="http://2sharings.com/category/sqlite">SqLite</a></li>
</ul>
</li>
<li><a href="~/home/about">關於我們</a></li>
<li><a href="~/home/contact">聯繫我們</a></li>
</ul>
<ul class="nav navbar-nav navbar-right navbar-profile">
<li><a href="~/account/register">免費註冊</a></li>
<li><a class="btn btn-primary nav-btn-login" href="~/account/login">立即登錄</a></li>
</ul>
</div><!--/.nav-collapse -->
</div>
</nav>
<div class="container">
<div class="jumbotron">
<h1>小伙伴,你好</h1>
<p>歡迎來到 Rector 的ASP.NET MVC 5 系列文章教程。在這裡,Rector將和你一起一步一步創建一個集成Repository+Autofac+Automapper+SqlSugar的WEB應用程式。</p>
<p>你準備好了嗎?</p>
<p>......</p>
<p>讓我們開始ASP.NET MVC 5 應用程式的探索之旅吧!!!</p>
</div>
<strong class="post-title">文章列表(@(Model.Count())篇)</strong>
<ul class="list-unstyled post-item-box">
@foreach (var p in Model)
{
<li>
<h2><a href="~/post/details/@p.Id">@p.Title</a></h2>
<p class="post-item-summary">@p.Summary ... <a href="~/post/details/@p.Id">閱讀全文</a></p>
</li>
}
</ul>
</div>
<footer class="footer-box">
<div class="container">
版權所有 © @(DateTime.Now.Year)
</div>
</footer>
<script src="~/Scripts/jquery-3.2.1.min.js"></script>
<script src="~/Scripts/bootstrap.min.js"></script>
</body>
</html>
後端介面與實現
在完成了前端頁面的佈局與製作之後,我們需要後端程式提供介面和服務,來供前端頁面調用,如首頁視圖中的視圖模型:
@model IEnumerable<TsBlog.ViewModel.Post.PostViewModel>
文章倉儲介面和實現
打開文件[IPostRepository.cs],在其中新增介面方法: FindHomePagePosts
,代碼如下:
using System.Collections.Generic;
using TsBlog.Domain.Entities;
namespace TsBlog.Repositories
{
public interface IPostRepository : IRepository<Post>
{
/// <summary>
/// 查詢首頁文章列表
/// </summary>
/// <param name="limit">要查詢的記錄數</param>
/// <returns></returns>
IEnumerable<Post> FindHomePagePosts(int limit = 20);
}
}
打開文件[PostRepository.cs],實現對應的介面方法:FindHomePagePosts
,代碼如下:
using SqlSugar;
using System.Collections.Generic;
using TsBlog.Domain.Entities;
namespace TsBlog.Repositories
{
/// <summary>
/// POST表的資料庫操作類
/// </summary>
public class PostRepository : GenericRepository<Post>, IPostRepository
{
#region Implementation of IPostRepository
/// <summary>
/// 查詢首頁文章列表
/// </summary>
/// <param name="limit">要查詢的記錄數</param>
/// <returns></returns>
public IEnumerable<Post> FindHomePagePosts(int limit = 20)
{
using (var db = DbFactory.GetSqlSugarClient())
{
var list = db.Queryable<Post>().OrderBy(x => x.Id, OrderByType.Desc).Take(limit).ToList();
return list;
}
}
}
#endregion
}
文章服務介面和實現
打開文件[IPostService.cs],在其中新增介面方法: FindHomePagePosts
,代碼如下:
using System.Collections.Generic;
using TsBlog.Domain.Entities;
namespace TsBlog.Services
{
public interface IPostService : IService<Post>
{
/// <summary>
/// 查詢首頁文章列表
/// </summary>
/// <param name="limit">要查詢的記錄數</param>
/// <returns></returns>
IEnumerable<Post> FindHomePagePosts(int limit = 20);
}
}
打開文件[PostService.cs],實現對應的介面方法:FindHomePagePosts
,代碼如下:
using System.Collections.Generic;
using TsBlog.Domain.Entities;
using TsBlog.Repositories;
namespace TsBlog.Services
{
public class PostService : GenericService<Post>, IPostService
{
private readonly IPostRepository _repository;
public PostService(IPostRepository repository) : base(repository)
{
_repository = repository;
}
#region Implementation of IPostService
/// <summary>
/// 查詢首頁文章列表
/// </summary>
/// <param name="limit">要查詢的記錄數</param>
/// <returns></returns>
public IEnumerable<Post> FindHomePagePosts(int limit = 20)
{
return _repository.FindHomePagePosts(limit);
}
#endregion
}
}
附加修改:重構了一下倉儲介面中的 FindListByClause
方法,將orderBy
參數設置為可空參數,具體實現如下:
/// <summary>
/// 根據條件查詢數據
/// </summary>
/// <param name="predicate">條件表達式樹</param>
/// <param name="orderBy">排序</param>
/// <returns>泛型實體集合</returns>
IEnumerable<T> FindListByClause(Expression<Func<T, bool>> predicate, string orderBy = "");
對應的修改泛型倉儲中的對應實現:
/// <summary>
/// 根據條件查詢數據
/// </summary>
/// <param name="predicate">條件表達式樹</param>
/// <param name="orderBy">排序</param>
/// <returns>泛型實體集合</returns>
public IEnumerable<T> FindListByClause(Expression<Func<T, bool>> predicate, string orderBy = "")
{
using (var db = DbFactory.GetSqlSugarClient())
{
var query = db.Queryable<T>().Where(predicate);
if (!string.IsNullOrEmpty(orderBy))
{
query = query.OrderBy(orderBy);
}
var entities = query.ToList();
return entities;
}
}
同樣的,服務層中也作相應的修改:
IService.cs 文件中的 FindListByClause
介面方法:
/// <summary>
/// 根據條件查詢數據
/// </summary>
/// <param name="predicate">條件表達式樹</param>
/// <param name="orderBy">排序</param>
/// <returns>泛型實體集合</returns>
IEnumerable<T> FindListByClause(Expression<Func<T, bool>> predicate, string orderBy = "");
泛型服務類:GenericService.cs 中的 FindListByClause
方法實現:
/// <summary>
/// 根據條件查詢數據
/// </summary>
/// <param name="predicate">條件表達式樹</param>
/// <param name="orderBy">排序</param>
/// <returns>泛型實體集合</returns>
public IEnumerable<T> FindListByClause(Expression<Func<T, bool>> predicate, string orderBy = "")
{
return _repository.FindListByClause(predicate, orderBy);
}
在開始處理HomeController控制器之前 ,我們先在項目[TsBlog.Core]中新建兩個幫助類,分別為:HtmlHelper.cs
和 StringHelper.cs
。其中代碼分別為:
HtmlHelper.cs
:
using System.Text.RegularExpressions;
namespace TsBlog.Core
{
public static class HtmlHelper
{
#region 去掉HTML中的所有標簽,只留下純文本
/// <summary>
/// 去掉HTML中的所有標簽,只留下純文本
/// </summary>
/// <param name="strHtml"></param>
/// <returns></returns>
public static string CleanHtml(this string strHtml)
{
if (string.IsNullOrEmpty(strHtml)) return strHtml;
//刪除腳本
strHtml = Regex.Replace(strHtml, "(\\<script(.+?)\\</script\\>)|(\\<style(.+?)\\</style\\>)", "", RegexOptions.IgnoreCase | RegexOptions.Singleline);
//刪除標簽
var r = new Regex(@"<\/?[^>]*>", RegexOptions.IgnoreCase);
Match m;
for (m = r.Match(strHtml); m.Success; m = m.NextMatch())
{
strHtml = strHtml.Replace(m.Groups[0].ToString(), "");
}
return strHtml.Trim();
}
#endregion
}
}
StringHelper.cs
:
using System;
namespace TsBlog.Core
{
public static class StringHelper
{
#region
/// <summary>
/// 截取指定長度的字元串
/// </summary>
/// <param name="str">原始字元串</param>
/// <param name="strLength">要保留的字元串長度</param>
/// <returns></returns>
public static string CutStrLength(this string str, int strLength)
{
var strNew = str;
if (string.IsNullOrEmpty(strNew)) return strNew;
var strOriginalLength = strNew.Length;
if (strOriginalLength > strLength)
{
strNew = strNew.Substring(0, strLength) + "...";
}
return strNew;
}
#endregion
#region
/// <summary>
/// 截取指定長度的字元串
/// </summary>
/// <param name="str">原始字元串</param>
/// <param name="strLength">要保留的字元串長度</param>
/// <param name="endWithEllipsis">是或以省略號(...)結束</param>
/// <returns></returns>
public static string CutStrLength(string str, int strLength, bool endWithEllipsis)
{
string strNew = str;
if (!strNew.Equals(""))
{
int strOriginalLength = strNew.Length;
if (strOriginalLength > strLength)
{
strNew = strNew.Substring(0, strLength);
if (endWithEllipsis)
{
strNew += "...";
}
}
}
return strNew;
}
#endregion
#region 截斷字元串(可保留完整單詞)
/// <summary>
/// 截斷字元串(可保留完整單詞)
/// </summary>
/// <param name="valueToTruncate">需處理的字元串</param>
/// <param name="maxLength">字元數</param>
/// <param name="options">截斷選項</param>
/// <returns></returns>
public static string TruncateString(this string valueToTruncate, int maxLength, TruncateOptions options)
{
if (valueToTruncate == null)
{
return "";
}
if (valueToTruncate.Length <= maxLength)
{
return valueToTruncate;
}
var includeEllipsis = (options & TruncateOptions.IncludeEllipsis) ==
TruncateOptions.IncludeEllipsis;
var finishWord = (options & TruncateOptions.FinishWord) ==
TruncateOptions.FinishWord;
var allowLastWordOverflow =
(options & TruncateOptions.AllowLastWordToGoOverMaxLength) ==
TruncateOptions.AllowLastWordToGoOverMaxLength;
var retValue = valueToTruncate;
if (includeEllipsis)
{
maxLength -= 1;
}
var lastSpaceIndex = retValue.LastIndexOf(" ",
maxLength, StringComparison.CurrentCultureIgnoreCase);
if (!finishWord)
{
retValue = retValue.Remove(maxLength);
}
else if (allowLastWordOverflow)
{
var spaceIndex = retValue.IndexOf(" ",
maxLength, StringComparison.CurrentCultureIgnoreCase);
if (spaceIndex != -1)
{
retValue = retValue.Remove(spaceIndex);
}
}
else if (lastSpaceIndex > -1)
{
retValue = retValue.Remove(lastSpaceIndex);
}
if (includeEllipsis && retValue.Length < valueToTruncate.Length)
{
retValue += "...";
}
return retValue;
}
#endregion
}
#region 截斷字元串用的枚舉
/// <summary>
/// 截斷字元串用的枚舉
/// </summary>
[Flags]
public enum TruncateOptions
{
/// <summary>
/// 不作任何處理
/// </summary>
None = 0x0,
/// <summary>
/// 保留完整單詞
/// </summary>
FinishWord = 0x1,
/// <summary>
/// 允許最後一個單詞超過最大長度限制
/// </summary>
AllowLastWordToGoOverMaxLength = 0x2,
/// <summary>
/// 字元串最後跟省略號
/// </summary>
IncludeEllipsis = 0x4
}
#endregion
}
在項[TsBlog.ViewModel]中的文章視圖文件[...TsBlog\src\Libraries\TsBlog.ViewModel\Post\PostViewModel.cs]中添加一個新的屬性:Summary
,此時的PostViewModel
是這樣的:
namespace TsBlog.ViewModel.Post
{
/// <summary>
/// 博文視圖實體類
/// </summary>
public class PostViewModel
{
/// <summary>
/// ID
/// </summary>
public int Id { get; set; }
/// <summary>
/// 標題
/// </summary>
public string Title { get; set; }
/// <summary>
/// 內容
/// </summary>
public string Content { get; set; }
/// <summary>
/// 作者ID
/// </summary>
public string AuthorId { get; set; }
/// <summary>
/// 作者姓名
/// </summary>
public string AuthorName { get; set; }
/// <summary>
/// 創建時間
/// </summary>
public string CreatedAt { get; set; }
/// <summary>
/// 發佈時間
/// </summary>
public string PublishedAt { get; set; }
/// <summary>
/// 是否標識已刪除
/// </summary>
public string IsDeleted { get; set; }
/// <summary>
/// 是否允許展示
/// </summary>
public bool AllowShow { get; set; }
/// <summary>
/// 瀏覽量
/// </summary>
public int ViewCount { get; set; }
/// <summary>
/// 摘要
/// </summary>
public string Summary { get; set; }
}
}
在項目[TsBlog.Frontend]中創建一個名為:Extensions
文件夾,併在其中創建一個文章的靜態擴展類[...\TsBlog.Frontend\Extensions\PostExtension.cs],同時實現以下靜態擴展方法:
using TsBlog.Core;
using TsBlog.ViewModel.Post;
namespace TsBlog.Frontend.Extensions
{
public static class PostExtension
{
/// <summary>
/// 格式化文章的視圖實體
/// </summary>
/// <param name="model">文章視圖實體類</param>
/// <returns></returns>
public static PostViewModel FormatPostViewModel(this PostViewModel model)
{
if (model == null)
{
return null;
}
model.Summary = model.Content
.CleanHtml() //去掉所有HTML標簽
.TruncateString(200, TruncateOptions.FinishWord | TruncateOptions.AllowLastWordToGoOverMaxLength); //截斷指定長度作為文章摘要
return model;
}
}
}
網站首頁[HomeController]
在首頁的控制器[...TsBlog.Frontend\Controllers\HomeController.cs]中,利用文章服務介面的方法實現首頁文章列表的查詢,代碼如下:
using System.Linq;
using System.Web.Mvc;
using TsBlog.AutoMapperConfig;
using TsBlog.Frontend.Extensions;
using TsBlog.Services;
namespace TsBlog.Frontend.Controllers
{
public class HomeController : Controller
{
/// <summary>
/// 文章服務介面
/// </summary>
private readonly IPostService _postService;
public HomeController(IPostService postService)
{
_postService = postService;
}
/// <summary>
/// 首頁
/// </summary>
/// <returns></returns>
public ActionResult Index()
{
var list = _postService.FindHomePagePosts();
var model = list.Select(x => x.ToModel().FormatPostViewModel());
return View(model);
}
}
}
好了,到此我們的首頁製作與數據綁定等到完成了,按F5運行,我們即可看到本文開篇所示的首頁效果。
文章詳情頁[PostController]
新建一個名為:PostController
的控制器,並添加如下代碼:
using System.Web.Mvc;
using TsBlog.AutoMapperConfig;
using TsBlog.Services;
namespace TsBlog.Frontend.Controllers
{
public class PostController : Controller
{
/// <summary>
/// 文章服務介面
/// </summary>
private readonly IPostService _postService;
public PostController(IPostService postService)
{
_postService = postService;
}
/// <summary>
/// 文章詳情
/// </summary>
/// <param name="id">文章ID</param>
/// <returns></returns>
public ActionResult Details(int id)
{
var post = _postService.FindById(id);
var model = post.ToModel();
return View(model);
}
}
}
再添加文章詳情頁的視圖[...\TsBlog.Frontend\Views\Post\Details.cshtml],添加如下視圖HTML代碼:
@model TsBlog.ViewModel.Post.PostViewModel
@{
Layout = null;
}
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>@(Model.Title) | TSBLOG</title>
<link href="~/Content/bootstrap.min.css" rel="stylesheet" />
<link href="~/resources/css/site.css" rel="stylesheet" />
</head>
<body>
<nav class="navbar navbar-default navbar-static-top ts-navbar">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="~/">網站名稱</a>
</div>
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li><a href="~/">網站首頁</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">分類導航 <span class="caret"></span></a>
<ul class="dropdown-menu">
<li class="dropdown-header">後端開發</li>
<li><a href="http://2sharings.com/category/csharp-development">C#程式設計</a></li>
<li><a href="http://2sharings.com/category/dot-net">.NET程式設計</a></li>
<li><a href="http://2sharings.com/category/asp-dot-net">ASP.NET</a></li>
<li><a href="http://2sharings.com/category/asp-net-mvc">ASP.NET MVC</a></li>
<li><a href="http://2sharings.com/category/asp-dotnet-core">ASP.NET Core</a></li>
<li><a href="http://2sharings.com/category/winform">Winform</a></li>
<li role="separator" class="divider"></li>
<li class="dropdown-header">資料庫</li>
<li><a href="http://2sharings.com/category/mysql">MySQL</a></li>
<li><a href="http://2sharings.com/category/sql-server">SQL Server</a></li>
<li><a href="http://2sharings.com/category/sqlite">SqLite</a></li>
</ul>
</li>
<li><a href="~/home/about">關於我們</a></li>
<li><a href="~/home/contact">聯繫我們</a></li>
</ul>
<ul class="nav navbar-nav navbar-right navbar-profile">
<li><a href="~/account/register">免費註冊</a></li>
<li><a class="btn btn-primary nav-btn-login" href="~/account/login">立即登錄</a></li>
</ul>
</div>
</div>
</nav>
<div class="container">
<h1 class="post-title">@Model.Title</h1>
<article class="article-content">
@Html.Raw(Model.Content)
</article>
</div>
<footer class="footer-box">
<div class="container">
版權所有 © @(DateTime.Now.Year)
</div>
</footer>
<script src="~/Scripts/jquery-3.2.1.min.js"></script>
<script src="~/Scripts/bootstrap.min.js"></script>
</body>
</html>
OK,今天這期的關於網站首頁及文章詳情頁面的佈局與製作就分享到這裡,希望對你瞭解ASP.NET MVC WEB應用程式開發有所幫助。
本期源碼托管地址:請至文章首發地址獲取《一步一步創建ASP.NET MVC5程式[Repository+Autofac+Automapper+SqlSugar](九)》
資料庫腳本文件請到目錄下查看:TsBlog\document\scripts\mysql\v1.9\
如果你喜歡Rector的本系列文章,請為我點個大大的贊。
**看完教程如果覺得還不過癮的,想“勾對”的,歡迎加入圖享網官方QQ群:483350228,如果你按照教程還原出來的程式運行有問題,請參照本期源碼對應調整與修改遇到問題的,也歡迎加入QQ群。有什麼,你懂的。。。^_^ **
謝謝你的耐心閱讀,本系列未完待續,我們下期再見……
本文首發於:圖享網 《一步一步創建ASP.NET MVC5程式[Repository+Autofac+Automapper+SqlSugar](九)》