首頁的思維是這樣的
- 是一個列表,預覽文章
- 左邊是Blog、右邊是sidebar
- 下方有頁碼
那麼立即開始
首先新建Controller/BlogController.cs、Models/Blog、Views/Blog/index.cshtml
給未寫過MVC的朋友簡單說明一下,Controller負責最外層接request,Model負責內部邏輯、view負責作為回傳給request的容器,可以是簡單一個int、一個JSON、或者一段html
所以完整的flow就是這樣
public class BlogController : Controller
{
public IActionResult Index()
{
List<Models.Blog> blogs = BlogFactory.GetBlogsByPage(1);
ViewData["Title"] = "";
return View(blogs);
}
}
這裡是Controller,Index()經BlogFactory這個class拿到List<Blog>,bind進/Views/Blog/index.cshtml,再傳回
為什麼是/Views/Blog呢其實M$很貼心地會根據Controller的名稱去找Views下面相同名稱的Folder,然後找哪個View就根據Method的名稱。你也可以不跟這個規則,比如return Views("folder2/abc.cshtml", blogs),它就會找Views/folder2/abc.cshtml
public class Blog
{
[Required]
public int Id { get; set; }
[Required]
[StringLength(200)]
public string Title { get; set; }
public string Markdown_Content { get; set; }
[Required]
[StringLength(50)]
public string Category { get; set; }
[StringLength(50)]
public string Tags { get; set; }
public int Author_Id { get; set; }
[StringLength(200)]
public string Thumbnail { get; set; }
[Required]
public DateTime Create_Ts { get; set; }
public DateTime Modify_Ts { get; set; }
public byte[] Password { get; set; }
[Required]
public bool Deleted { get; set; }
[Required]
public bool NoComment { get; set; }
[Required]
public bool NoRobots { get; set; }
public int view_count { get; set; }
}
這個是Blog class,和DB的table有一樣的fields,使用dapper這個ORM framework可以將從db query到的數據直接轉換成Blog物件,有興趣可以google一下,我認為比Entity Framework方便得多
@model IEnumerable<Blog>
<link rel="stylesheet" href="~/lib/highlight/styles/vs2015.css">
<script src="~/lib/highlight/highlight.pack.js"></script>
<script>hljs.initHighlightingOnLoad();</script>
<div id="blogBody" class="col-md-9">
@if (ViewData["CurrentRoute"] != null)
{
<div class="blogPost">
<a class="blogTitle">Searching: @ViewData["CurrentRoute"]</a>
</div>
}
@foreach (Blog blog in Model)
{
<div class="blogPost">
<a class="blogTitle" href="/blog/@blog.Id">@blog.Title</a>
<div class="header">
<small class="gray headerItems">@blog.Create_Ts.ToString("yyyy-MM-dd hh:mm")</small>
@if(blog.Modify_Ts != null){
<small class="gray headerItems">Last Edited: @(((DateTime)blog.Modify_Ts).ToString("yyyy-MM-dd hh:mm"))</small>
}
@{Random rnd = new Random();
int ranComment = rnd.Next(1, 13);
int ranReadCount = rnd.Next(1, 10000);
}
<small class="gray view_count headerItems">@string.Format("{0:n0}", blog.view_count)</small>
<small class="orange comment_count headerItems">(@ranComment)</small>
</div>
<div class="blogContent">
@(blog.Markdown_Content == null ? "" : new string(System.Text.RegularExpressions.Regex.Replace(blog.Markdown_Content, "<.*?>", String.Empty).Take(200).ToArray()))
<a href="/blog/@blog.Id" class="l">@(blog.Markdown_Content != null && blog.Markdown_Content.Count() > 200 ? "...(more)" : "")</a>
</div>
<div class="blogFooter">
<div class="category">
Category:
<a href="/category/@blog.Category" class="l">@blog.Category</a>
</div>
@if (!string.IsNullOrEmpty(blog.Tags))
{
<div class="tags">
Tags:
@foreach (var item in blog.Tags.Split(','))
{
if (item != "")
{<a href="/tag/@item.Trim()" class="l" style="margin-right:4px">@item.Trim()</a>}
}
</div>
}
</div>
</div>
}
<partial name="~/Views/Shared/_pagination.cshtml" />
</div>
<partial name="~/Views/Shared/_sidebar.cshtml" />
以上是cshtml,第一行@model IEnumerable<Blog>表示這個頁可以綁定的Model是IEnumerable,
中間可以看見我會先iterate list<model>一次
當經index進來時會透過blogFactory傳頭10行blog放進list<blog>傳進這個View
然後就foreach這個List,每個blog創生一個blogPost,裡面有header、content、footer等
Foreach完結後再加上pagination頁碼的partial view和sidebar
#blogBody {
float: left;
/*width: 75%;
margin-left: 5px;
margin-right: 5px;*/
overflow: hidden;
}
#sidebar {
margin-top: 40px;
/*width: 20%;*/
float: left;
font-family: 'Lucida Sans', 'Lucida Grande', 'Lucida Sans Unicode', sans-serif;
}
至於layout則用css和bootstrap處理,bootstrap是一種responsive web design的framework,新增.net core mvc時已經自動包含
#blogBody的class設成col-md-9,這個"col-md-9"就是bootstrap的class,它會將目前的空間等分成12個column,col-md-9即是佔9個column的闊度,中間的md是指middle,即電腦瀏覽時使用。如果要指定手機瀏覽時的layout,可以再加一個class,比如col-xs-12,則會佔全個畫面闊度。透過不同的class指定不同device上瀏覽時的布局,就是bootstrap其中一個功能。
設定成float是為了讓兩個element都共存同一行,不會撞開。(大概是,不太懂css)
闊度設好後,我還把兩個blogBody和sidebar都設定成float align to left,當blogBody已經大到不足以給sidebar空間時,sidebar就可以自動排到下方。如果我都它設成float to right,則blogBody和sidebar會自動縮小到可以一個align to left一個align to right的大小,會變得太小不好看。
Blog專案 - 初步結構
Blog專案 - 內文 (Controller, view)