iT邦幫忙

2022 iThome 鐵人賽

0
自我挑戰組

用 30 天和 ASP.NET Core 打造一個活動報名管理系統系列 第 29

ASP.NET Core - 活動報名管理系統:Day29 讓畫面更好看,Bootstrap Card 的呈現與 View Component

  • 分享至 

  • xImage
  •  

前言

目前系統的頁面還是使用 ASP.NET Core MVC 的原始版面,看上去其實也不太美觀,剛好它本來就有使用 Bootstrap,那麼今天就使用 Bootstrap 的 Card 元件來讓活動列表更好看。

也會使用 View Component,藉由 View Component 來讓頁面顯示幻燈片的元件,其中幻燈片展示的是現在的活動以及該活動上傳的圖片。

Views

Index

將原本的 Code 刪除,並貼上以下 Code:

<div class="row">
    <div class="col-lg-12">
        <h4>精選活動</h4>
        <hr />
        <div class="row">
            @foreach (var e in Model.EventsCollection)
            {
                <div class="col-lg-4">
                    <div class="card" style="width: 18rem;">
                        @if (e.EventsImage.Count() > 0)
                        {
                            <img src="~/images/Upload/Events/@e.EventsImage.FirstOrDefault().ImageFilePath" class="card-img-top" asp-append-version="true" />
                        }
                        else
                        {
                            <img src="~/images/logo.png" class="card-img-top" alt="...">
                        }
                        <div class="card-body">
                            <h5 class="card-title">@e.Title</h5>
                            <h6 class="card-subtitle mb-2 text-muted">@e.ProgressTimeStart.ToString("yyyy-MM-dd(dddd)") ~ <br>@e.ProgressTimeStart.ToString("yyyy-MM-dd(dddd)")</h6>
                            <p class="card-text">@e.SimpleIntro</p>
                            <a asp-controller="Events" asp-action="Details" asp-route-Id="@e.Id" class="btn btn-primary">查看更多</a>
                        </div>
                    </div>
                </div>
            }
        </div>
    </div>
</div>

迴圈判斷 EventsImage 數量是否大於 0,若有則顯示已上傳的圖片;
若無則顯示預設 Logo。
並且將活動名稱、簡稱、活動時間等放在 Card 的顯示欄位中。

View Component

View Component 與 Partial View 的差異在於,Partial View 主要是減少重複的 HTML,而 View Component 就像是一個小型 Controller 與 View 的結合。

View Component 可以在後端撰寫商業邏輯,或是寫入一些第三方的套件,並且在任何地方皆可呼叫,e.g. 購物車、Facebook Messenger API 等。

而這裡我會使用在 Bootstrap 的投影片元件上,後端則是呼叫最新的活動。

後端程式

在專案新增 ViewComponents 的資料夾,並新增 ShowEventsCarousel 類別:

public async Task<IEnumerable<Events>> GetTheNewestEventsAsync(int count)
        {
            string SqlScript = $"EXECUTE dbo.GetTheNewestEvents @Count = {count}";
            var events = await _appDbContext.Events.FromSqlRaw(SqlScript).ToListAsync();

            foreach (var item in events)
            {
                item.EventsInfo = _appDbContext.EventsInfo.Where(
                    ei => ei.EventsInfoOfEventsId == item.Id
                    ).FirstOrDefault();

                item.EventsImage = _appDbContext.EventsImage.Where(
                    ei => ei.EventsId == item.Id
                    ).ToList();
            }

            return events;
        }

前端程式

在 Views/Shared 新增 Components/ShowEventsCarousel 資料夾,再新增 Default.cshtml 檔案:

@model EventsListViewModel

<div class="row">
    <div class="col-lg-12">
        <div id="carouselExampleIndicators" class="carousel slide" data-ride="carousel">
            <ol class="carousel-indicators">
                @for (int i = 0; i < Model.EventsCollection.ToList().Count; i++)
                {
                    if (i == 0)
                    {
                        <li data-target="#carouselExampleIndicators" data-slide-to="@i" class="active"></li>
                    }
                    else
                    {
                        <li data-target="#carouselExampleIndicators" data-slide-to="@i"></li>
                    }
                }
            </ol>
            <div class="carousel-inner">
                @for (int i = 0; i < Model.EventsCollection.ToList().Count; i++)
                {
                    if (i == 0)
                    {
                        <div class="carousel-item active">
                            <a asp-controller="Events" asp-action="Details" asp-route-Id="@Model.EventsCollection.ToList()[i].Id">
                                @{
                                    if (@Model.EventsCollection.ToList()[i].EventsImage.Count() > 0)
                                    {
                                        <img class="d-block w-100" src="~/images/Upload/Events/@Model.EventsCollection.ToList()[i].EventsImage.FirstOrDefault().ImageFileName" alt="@Model.EventsCollection.ToList()[i].Title">
                                    }
                                    else
                                    {
                                        <img class="d-block w-100" src="~/images/logo.png" alt="@Model.EventsCollection.ToList()[i].Title">
                                    }
                                }
                            </a>
                        </div>
                    }
                    else
                    {
                        <div class="carousel-item">
                            <a asp-controller="Events" asp-action="Details" asp-route-Id="@Model.EventsCollection.ToList()[i].Id">
                                @{
                                    if (@Model.EventsCollection.ToList()[i].EventsImage.Count() > 0)
                                    {
                                        <img class="d-block w-100" src="~/images/Upload/Events/@Model.EventsCollection.ToList()[i].EventsImage.FirstOrDefault().ImageFileName" alt="@Model.EventsCollection.ToList()[i].Title">
                                    }
                                    else
                                    {
                                        <img class="d-block w-100" src="~/images/logo.png" alt="@Model.EventsCollection.ToList()[i].Title">
                                    }
                                }
                            </a>
                        </div>
                    }
                }
            </div>
        </div>
        <a class="carousel-control-prev" href="#carouselExampleIndicators" role="button" data-slide="prev">
            <span class="carousel-control-prev-icon" aria-hidden="true"></span>
            <span class="sr-only">Previous</span>
        </a>
        <a class="carousel-control-next" href="#carouselExampleIndicators" role="button" data-slide="next">
            <span class="carousel-control-next-icon" aria-hidden="true"></span>
            <span class="sr-only">Next</span>
        </a>
    </div>
</div>

<style>
    .carousel-item {
        height: 400px;
    }

        .carousel-item img {
            height: 400px;
        }
</style>

EventsRepository

建立一個可以取得最新建立的活動,並可以指定傳回多少筆數的資料,而取資料的方式是再撰寫一個 Stored Procedure:

public async Task<IEnumerable<Events>> GetTheNewestEventsAsync(int count)
        {
            string SqlScript = $"EXECUTE dbo.GetTheNewestEvents @Count = {count}";
            var events = await _appDbContext.Events.FromSqlRaw(SqlScript).ToListAsync();

            return events;
        }

Stored Procedure

USE EventsSystem
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

CREATE PROCEDURE [GetTheNewestEvents]
	@Count INT = 5
AS
BEGIN	
	SET NOCOUNT ON;
	DECLARE @SQLScript NVARCHAR(MAX)
	SET @SQLScript = 
	'
		SELECT TOP (' + CAST(@Count AS VARCHAR(5)) + ') T_E.[Id]
		  ,T_E.[Title]
		  ,T_EI.[Location]
		  ,T_E.[SimpleIntro]
          ,T_E.[CategoryId]
		  ,T_E.[ProgressTimeStart]
		  ,T_E.[ProgressTimeEnd]
		  ,T_E.[SaleTimeStart]
		  ,T_E.[SaleTimeEnd]
		  ,T_EI.[ApplicationLimitedQty]
		  ,T_EI.[EventsApplicationQty]
		  ,T_E.[CreateTime]
		  ,T_E.[CreateUser]
		  ,T_E.[UpdateTime]
		  ,T_E.[UpdateUser]
		FROM [dbo].[Events] AS T_E
        LEFT JOIN [dbo].[EventsInfo] AS T_EI
        ON T_E.[Id] = T_EI.[EventsInfoOfEventsId]
		ORDER BY T_E.[CreateTime] DESC 
	'

	EXEC (@SQLScript)
END
GO

_ViewImports.cshtml

加入參考 @using EventsSystem_iThome.ViewComponents

Index.cshtml

加入 @await Component.InvokeAsync(nameof(ShowEventsCarousel))

實際成果

本日結語

實際用上 View Component 或是 Partial View,都可以讓 HTML 本身的 Code 減少很多,而且重用性很高,比如說今天要抓出站台的總瀏覽人數,就可以寫在 View Component 並且在各種不同的頁面呼叫。

對了,鐵人賽斷在 28 天的原因下一篇會說~
下一篇會寫下這整個月的心路歷程,以及一些領悟到的事情。

那麼明天見~

Reference

[鐵人賽Day13] - View(3) / Partial View及View Component


上一篇
ASP.NET Core - 活動報名管理系統:Day28 用 Partial View 顯示 Bootstrap Alert 以及改善活動功能的執行權限
下一篇
Day 30 一些感想
系列文
用 30 天和 ASP.NET Core 打造一個活動報名管理系統30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言