0%

【MVC教學】8.View(一)

Demo範例 :Git位置

#目標

將網路上下載來的免費漂亮版型套進專案中,從實作中瞭解如何套版跟應用.Net提供的一些API方法,過程中或許會有許多小地方不懂,例如Html結構,View Render的機制等等,沒關係,這會在後續的篇章中慢慢補足,而此篇主要是希望讓讀者知道套版原理,並享受網頁隨著套版變漂亮的過程。

在Google搜尋中輸入free template download可以找到一大堆免費授權的版型,而這次從這個TEMPLATED挑了一個喜歡的,有興趣可以先看一下該版型的Live Demo

/images/20180627/1.jpg

如果不方便從網路下載也無妨,我已經將下載好且解壓的版本放到Git的專案之中,如果要練習可以直接從裡面取得Source Code

/images/20180627/2.jpg

#實作

套版前準備

Chrome

通常我會用Chrome瀏覽器來輔助套版的工作,所以以下的操作都是針對Chrome撰寫,不過現在各家瀏覽器其實都大同小異了,只要有相對應的功能即可。

Web Server For Chrome(非必要)

為了方便瀏覽下載的版型,可以安裝Web Server For Chrome這個套件

/images/20180627/3.jpg

安裝完後應該會在Chrome的應用程式中看到Web Server

/images/20180627/4.jpg

打開它並把資料夾選到版型的根目錄

/images/20180627/5.jpg

/images/20180627/6.jpg

點擊**Web Server URL(s)**,應該就可以看到網站出現了

/images/20180627/7.jpg

/images/20180627/8.jpg

首頁套版

從Visual Studio中開啟Index.html

/images/20180627/9.jpg

/images/20180627/10.jpg

所有內容複製貼到我們的/Home/Index.cshtml之中

/images/20180627/11.jpg

這時候會發現第一個錯誤

/images/20180627/12.jpg

跳脫字元

原因是.Net MVC預設用的套版語法是Razor,而**@是它的保留字,所以要用跳脫字元來解決,只要將*@*templatedco變成@@templatedco**,它在顯示網頁的時候就會印出我們想要的@templatedco了

/images/20180627/13.jpg

執行網站看首頁結果會發現,它怪怪的…

/images/20180627/14.jpg

Layout

首先網頁最上面那排黑黑的Header,明明我們版型的Header沒這塊,它是從哪邊長出來的?

這邊就要瞭解Layout是什麼

/images/20180627/15.jpg

很多網頁都會有一個特性,那就是不管切換到哪個頁面都會有共用的區塊,以Sony頁面為例

PlayStation頁面

/images/20180627/16.jpg

消費性電子>電視頁面

/images/20180627/17.jpg

共通點就是Header不管到哪一頁都不會換

/images/20180627/18.jpg

而如果每頁都要重新把Header套版一次會衍伸一些問題

  • 重工 : 有一百頁就要把一樣的內容貼一百次
  • 維護困難 : 如果想在Header多一顆按鈕,就要打開一百個頁面調整一百次

所以實務上會透過Layout來解決這問題,將全站幾乎都會共用的部分抽出來當Layout,而會變動的部分當作Body

所以套用了新的版型還會跑出Header,那是因為Layout裡面有這個區塊

/images/20180627/19.jpg

依照剛剛說的,我們把共用的區塊抽到Layout裡面去放

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!DOCTYPE HTML>
<!--
Hielo by TEMPLATED
templated.co @@templatedco
Released for free under the Creative Commons Attribution 3.0 license (templated.co/license)
-->
<html>
<head>
<title>Hielo by TEMPLATED</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="assets/css/main.css" />
</head>
<body>
....
</body>
</html>

Layout調整成

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<!DOCTYPE HTML>
<!--
Hielo by TEMPLATED
templated.co @@templatedco
Released for free under the Creative Commons Attribution 3.0 license (templated.co/license)
-->
<html>
<head>
<title>Hielo by TEMPLATED</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="assets/css/main.css" />
</head>
<body>
@RenderBody()

@RenderSection("scripts", required: false)
<script>
@if (TempData["Message"] != null)
{
<text>alert('@TempData["Message"]')</text>
}
</script>
</body>
</html>

Index調整成

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
@{
ViewBag.Title = "Home Page";
}



<!-- Header -->
<header id="header" class="alt">
<div class="logo"><a href="index.html">Hielo <span>by TEMPLATED</span></a></div>
<a href="#menu">Menu</a>
</header>

<!-- Nav -->
<nav id="menu">
<ul class="links">
<li><a href="index.html">Home</a></li>
<li><a href="generic.html">Generic</a></li>
<li><a href="elements.html">Elements</a></li>
</ul>
</nav>

<!-- Banner -->
<section class="banner full">
<article>
<img src="images/slide01.jpg" alt="" />
<div class="inner">
<header>
<p>A free responsive web site template by <a href="https://templated.co">TEMPLATED</a></p>
<h2>Hielo</h2>
</header>
</div>
</article>
<article>
<img src="images/slide02.jpg" alt="" />
<div class="inner">
<header>
<p>Lorem ipsum dolor sit amet nullam feugiat</p>
<h2>Magna etiam</h2>
</header>
</div>
</article>
<article>
<img src="images/slide03.jpg" alt="" />
<div class="inner">
<header>
<p>Sed cursus aliuam veroeros lorem ipsum nullam</p>
<h2>Tempus dolor</h2>
</header>
</div>
</article>
<article>
<img src="images/slide04.jpg" alt="" />
<div class="inner">
<header>
<p>Adipiscing lorem ipsum feugiat sed phasellus consequat</p>
<h2>Etiam feugiat</h2>
</header>
</div>
</article>
<article>
<img src="images/slide05.jpg" alt="" />
<div class="inner">
<header>
<p>Ipsum dolor sed magna veroeros lorem ipsum</p>
<h2>Lorem adipiscing</h2>
</header>
</div>
</article>
</section>

<!-- One -->
<section id="one" class="wrapper style2">
<div class="inner">
<div class="grid-style">

<div>
<div class="box">
<div class="image fit">
<img src="images/pic02.jpg" alt="" />
</div>
<div class="content">
<header class="align-center">
<p>maecenas sapien feugiat ex purus</p>
<h2>Lorem ipsum dolor</h2>
</header>
<p> Cras aliquet urna ut sapien tincidunt, quis malesuada elit facilisis. Vestibulum sit amet tortor velit. Nam elementum nibh a libero pharetra elementum. Maecenas feugiat ex purus, quis volutpat lacus placerat malesuada.</p>
<footer class="align-center">
<a href="#" class="button alt">Learn More</a>
</footer>
</div>
</div>
</div>

<div>
<div class="box">
<div class="image fit">
<img src="images/pic03.jpg" alt="" />
</div>
<div class="content">
<header class="align-center">
<p>mattis elementum sapien pretium tellus</p>
<h2>Vestibulum sit amet</h2>
</header>
<p> Cras aliquet urna ut sapien tincidunt, quis malesuada elit facilisis. Vestibulum sit amet tortor velit. Nam elementum nibh a libero pharetra elementum. Maecenas feugiat ex purus, quis volutpat lacus placerat malesuada.</p>
<footer class="align-center">
<a href="#" class="button alt">Learn More</a>
</footer>
</div>
</div>
</div>

</div>
</div>
</section>

<!-- Two -->
<section id="two" class="wrapper style3">
<div class="inner">
<header class="align-center">
<p>Nam vel ante sit amet libero scelerisque facilisis eleifend vitae urna</p>
<h2>Morbi maximus justo</h2>
</header>
</div>
</section>

<!-- Three -->
<section id="three" class="wrapper style2">
<div class="inner">
<header class="align-center">
<p class="special">Nam vel ante sit amet libero scelerisque facilisis eleifend vitae urna</p>
<h2>Morbi maximus justo</h2>
</header>
<div class="gallery">
<div>
<div class="image fit">
<a href="#"><img src="images/pic01.jpg" alt="" /></a>
</div>
</div>
<div>
<div class="image fit">
<a href="#"><img src="images/pic02.jpg" alt="" /></a>
</div>
</div>
<div>
<div class="image fit">
<a href="#"><img src="images/pic03.jpg" alt="" /></a>
</div>
</div>
<div>
<div class="image fit">
<a href="#"><img src="images/pic04.jpg" alt="" /></a>
</div>
</div>
</div>
</div>
</section>


<!-- Footer -->
<footer id="footer">
<div class="container">
<ul class="icons">
<li><a href="#" class="icon fa-twitter"><span class="label">Twitter</span></a></li>
<li><a href="#" class="icon fa-facebook"><span class="label">Facebook</span></a></li>
<li><a href="#" class="icon fa-instagram"><span class="label">Instagram</span></a></li>
<li><a href="#" class="icon fa-envelope-o"><span class="label">Email</span></a></li>
</ul>
</div>
<div class="copyright">
&copy; Untitled. All rights reserved.
</div>
</footer>

<!-- Scripts -->
<script src="assets/js/jquery.min.js"></script>
<script src="assets/js/jquery.scrollex.min.js"></script>
<script src="assets/js/skel.min.js"></script>
<script src="assets/js/util.js"></script>
<script src="assets/js/main.js"></script>

@RenderBody()

Layout中間有一行@RenderBody()這是Razor提供的方法,意思是所有套用這個Layout的頁面,它的內容會取代@RenderBody()。

假設我們的Index內容為

1
<p>I'm Index</p>

那套上Layout後產生給使用者看到的完整Html就會是這樣

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!DOCTYPE HTML>
<!--
Hielo by TEMPLATED
templated.co @@templatedco
Released for free under the Creative Commons Attribution 3.0 license (templated.co/license)
-->
<html>
<head>
<title>Hielo by TEMPLATED</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="assets/css/main.css" />
</head>
<body>
<p>I'm Index</p>
.....
</body>
</html>

@RenderSection()

實務上會希望Javascript或是CSS在特定的地方載入,如果只是單純放在Index中將會變成這樣

Index

1
2
<p>I'm Index</p>
<script src="assets/js/jquery.min.js"></script>

結果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!DOCTYPE HTML>
<!--
Hielo by TEMPLATED
templated.co @@templatedco
Released for free under the Creative Commons Attribution 3.0 license (templated.co/license)
-->
<html>
<head>
<title>Hielo by TEMPLATED</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="assets/css/main.css" />
</head>
<body>
<p>I'm Index</p>
<script src="assets/js/jquery.min.js"></script>
....
</body>
</html>

此時就可以透過在Layout中挖**@RenderSection()**區塊來解決

Layout

1
2
3
4
5
6
7
8
9
10
11
12
13
<!DOCTYPE HTML>
<html>
<head>
....
@RenderSection("css", required: false)
</head>
<body>
@RenderBody()

@RenderSection("scripts", required: false)
....
</body>
</html>

Index

1
2
3
4
5
6
7
8
@section scripts{
<script src="assets/js/jquery.min.js"></script>
}
@section css{
<link rel="stylesheet" href="assets/css/main.css" />
}

<p>I'm Index</p>

結果

1
2
3
4
5
6
7
8
9
10
11
12
13
<!DOCTYPE HTML>
<html>
<head>
....
<link rel="stylesheet" href="assets/css/main.css" />
</head>
<body>
<p>I'm Index</p>

<script src="assets/js/jquery.min.js"></script>
....
</body>
</html>

@RenderSection(“scripts”, required: false)

required參數意義為

True :套用這個Layout的子版面一定要寫@section scripts{ }這個區段

False :套用這個Layout的子版面可以沒有@section scripts{ }區段

_ViewStart

檢視Index頁面,為何它知道要套用Layout呢?其實這寫在_ViewStart.cshtml之中

/images/20180627/20.jpg

_ViewStart.cshtml

1
2
3
@{
Layout = "~/Views/Shared/_Layout.cshtml";
}

所有頁面如果沒有特別指定Layout的情況下,預設套用這個設定。

但這不意謂著不能自行修改,假設所有專案有兩三個頁面要套用_Layout2.cshtml,那我們可以在各自的頁面中指定Layout,而指定的Layout優先於預設。

Index

1
2
3
4
@{
Layout = "~/Views/Shared/_Layout2.cshtml";
}
<p>I'm Index</p>

載入CSS、Javascript

重新調整Layout與Index內容後,頁面依然沒有正常顯示

/images/20180627/21.jpg

在Chrome按下F12點擊右上角的錯誤可以得知是因為沒有載入CSS與Javascript

/images/20180627/22.jpg

將Javascript與CSS移到專案之中

/images/20180627/23.jpg

/images/20180627/24.jpg

同時我們也刪除掉原本在專案內的Javascript與CSS

修改Index中Javascript的位置

1
2
3
4
5
6
7
8
9
....

<!-- Scripts -->
<script src="~/assets/js/jquery.min.js"></script>
<script src="~/assets/js/jquery.min.js"></script>
<script src="~/assets/js/jquery.scrollex.min.js"></script>
<script src="~/assets/js/skel.min.js"></script>
<script src="~/assets/js/util.js"></script>
<script src="~/assets/js/main.js"></script>

修改_Layout中CSS的位置

1
2
3
4
5
6
7
8
...
<head>
<title>Hielo by TEMPLATED</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link href="~/assets/css/main.css" rel="stylesheet" />
</head>
...

~/assets/css/main.css

~/assets/js/main.js

前面的 ~ 符號表示從根目錄開始算起

再次執行專案

發生錯誤,原因是BundleConfig的地方有抓原本放Javascript的資料夾但被我們砍掉了,Bundle基本上目前我們很少用到所以先暫時不理它,把內容清空不影響結果

1
2
3
4
5
6
7
public class BundleConfig
{
// 如需統合的詳細資訊,請瀏覽 https://go.microsoft.com/fwlink/?LinkId=301862
public static void RegisterBundles(BundleCollection bundles)
{
}
}

執行起來後

/images/20180627/25.jpg

看起來正常許多但圖片還是沒有出來,將圖片移入

/images/20180627/26.jpg

/images/20180627/27.jpg

#小結

/images/20180627/28.jpg

已經成功將首頁移入專案之中,下一篇將來客製化將之前完成的登入頁面也套進這個漂亮的版型之中,中間將會碰到更多套版的Razor API與一些小技巧。