iT邦幫忙

2022 iThome 鐵人賽

DAY 29
0

https://i.imgur.com/Qry1RgI.jpg

功能實作 : Demo

一、前言

今天的目標是將現有的組件組成一個 SPA 網頁,最終目標是先把網頁寫出來,至於優化和除錯的部分,就要等整個功能都實作出來之後,再來慢慢修正,那麼我們就先來看看整合了哪些東西吧~


二、組件集大成 - 上篇

以 CodePen 為例。

2.1 前置作業

先在 CodePen 中加入 Bootstrap。

JavaScript:

https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.2.2/js/bootstrap.min.js

CSS:

https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.0.2/css/bootstrap.min.css

在HTML 加入 Font Awesome

HTML:

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">

CSS:(起手式)

* {
	margin: 0;
	padding: 0;
	list-style: none;
	box-sizing: border-box;
	font-family: Helvetica, sans-serif;
}

html,
body {
	width: 100%;
	height: 100%;
}

CSS:(內容視窗相關設定)

section {
	color: #333;
}

section h1 {
	text-align: center;
	font-size: 2rem;
}

section h1 + p {
	text-align: center;
	font-size: 1rem;
	font-weight: 600;
	padding: 25px;
}

CSS:(製造間隔-類似水平線功能)

.break {
	width: 100%;
	height: 100px;
}

.purple {
	background-color: #dbc8e7;
}

2.2 NAV Bar

直接使用 Bootstrap v5.0 【1】提供的 Navbar。

HTML:

<nav class="navbar navbar-expand-lg navbar-light bg-light">
	<div class="container-fluid">
		<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarTogglerDemo03" aria-controls="navbarTogglerDemo03" aria-expanded="false" aria-label="Toggle navigation">
			<span class="navbar-toggler-icon"></span>
		</button>
		<a class="navbar-brand" href="#">Navbar</a>
		<div class="collapse navbar-collapse" id="navbarTogglerDemo03">
			<ul class="navbar-nav me-auto mb-2 mb-lg-0">
				<li class="nav-item">
					<a class="nav-link active" aria-current="page" href="#">Home</a>
				</li>
				<li class="nav-item">
					<a class="nav-link" href="#">Link</a>
				</li>
				<li class="nav-item">
					<a class="nav-link disabled" href="#" tabindex="-1" aria-disabled="true">Disabled</a>
				</li>
			</ul>
			<form class="d-flex">
				<input class="form-control me-2" type="search" placeholder="Search" aria-label="Search" />
				<button class="btn btn-outline-success" type="submit">Search</button>
			</form>
		</div>
	</div>
</nav>

顯示結果:

https://i.imgur.com/oK7NI7x.jpg

2.3 Header

HTML:

<header>
	<img src="https://i.imgur.com/5pEwv5L.jpg" alt="" />
</header>

CSS:

img {
	width: 100%;
	object-fit: contain;
}

顯示結果:

https://i.imgur.com/qC9CYvU.jpg

2.4 Modal

HTML:

<div id="modal" class="modal"></div>

CSS:

.modal {
	width: 100%;
	height: 100%;
	padding: 5px;
	background-color: white;
	position: fixed;
	left: 0;
	top: 0;
	z-index: 1;
	transition: 1s;
	display: block;
}

/* 圖片滿版 */
.modal:before {
	content: "";
	display: block;
	position: fixed;
	left: 0;
	top: 0;
	width: 100%;
	height: 100%;
	z-index: -10;
	background: url(https://i.imgur.com/6TKAygG.gif) no-repeat center center;
	-webkit-background-size: cover;
	-moz-background-size: cover;
	-o-background-size: cover;
	background-size: cover;
	padding-bottom: 20%;
}

JavaScript:

window.onload = () => {
	setTimeout(() => {
		$("#modal").fadeOut(1000);
	}, 1000);
};

setTimeout 用法可參考這裡【1】

顯示結果:

https://i.imgur.com/OT3w6e0.gif


三、組件集大成 - 下篇

3.1 Card

Card 主要用來表示作品集。

HTML:

<section class="section__portfolio">
	<div class="break"></div>
	<h1>Portfolio</h1>
	<div class="containerx">
		<div class="card">
			<div class="card__block">
				<div class="card__img">
					<img src="https://source.unsplash.com/random/400x300?sig=1" />
				</div>
				<div class="time__block">
					<div class="time__icon"><i class="fa fa-clock-o" aria-hidden="true"></i></div>
					<div class="time__text">22:00</div>
				</div>
				<div class="card__heart"><i class="fa fa-heart-o" aria-hidden="true"></i></div>
				<div class="video__block">
					<div class="video__icon"><i class="fa fa-youtube-play" aria-hidden="true"></i></div>
					<div class="video__text">第9集</div>
				</div>
			</div>
			<div class="content">
				<div class="content__title">
					<div class="marquee__text">OVERLORD</div>
				</div>
				<div class="contrnt__item">
					<div class="content__icon"><i class="fa fa-eye" aria-hidden="true"></i></div>
					<div class="content__number">197.1萬</div>
				</div>
			</div>
		</div>

		<div class="card">
			<div class="card__block">
				<div class="card__img">
					<img src="https://source.unsplash.com/random/400x300?sig=2" />
				</div>
				<div class="time__block">
					<div class="time__icon"><i class="fa fa-clock-o" aria-hidden="true"></i></div>
					<div class="time__text">23:00</div>
				</div>
				<div class="card__heart"><i class="fa fa-heart-o" aria-hidden="true"></i></div>
				<div class="video__block">
					<div class="video__icon"><i class="fa fa-youtube-play" aria-hidden="true"></i></div>
					<div class="video__text">第9集</div>
				</div>
			</div>
			<div class="content">
				<div class="content__title">
					<div class="marquee__text">來自深淵 烈日的黃金鄉</div>
				</div>
				<div class="contrnt__item">
					<div class="content__icon"><i class="fa fa-eye" aria-hidden="true"></i></div>
					<div class="content__number">109.2萬</div>
				</div>
			</div>
		</div>

		<div class="card">
			<div class="card__block">
				<div class="card__img">
					<img src="https://source.unsplash.com/random/400x300?sig=3" />
				</div>
				<div class="time__block">
					<div class="time__icon"><i class="fa fa-clock-o" aria-hidden="true"></i></div>
					<div class="time__text">22:05</div>
				</div>
				<div class="card__heart"><i class="fa fa-heart-o" aria-hidden="true"></i></div>
				<div class="video__block">
					<div class="video__icon"><i class="fa fa-youtube-play" aria-hidden="true"></i></div>
					<div class="video__text">第7集</div>
				</div>
			</div>
			<div class="content">
				<div class="content__title">
					<div class="marquee__text">在地下城尋求邂逅是否搞錯了什麼 第四季</div>
				</div>
				<div class="contrnt__item">
					<div class="content__icon"><i class="fa fa-eye" aria-hidden="true"></i></div>
					<div class="content__number">106.9萬</div>
				</div>
			</div>
		</div>

		<div class="card">
			<div class="card__block">
				<div class="card__img">
					<img src="https://source.unsplash.com/random/400x300?sig=4" />
				</div>
				<div class="time__block">
					<div class="time__icon"><i class="fa fa-clock-o" aria-hidden="true"></i></div>
					<div class="time__text">23:00</div>
				</div>
				<div class="card__heart"><i class="fa fa-heart-o" aria-hidden="true"></i></div>
				<div class="video__block">
					<div class="video__icon"><i class="fa fa-youtube-play" aria-hidden="true"></i></div>
					<div class="video__text">第12集</div>
				</div>
			</div>
			<div class="content">
				<div class="content__title">
					<div class="marquee__text">SPY×FAMILY 間諜家家酒</div>
				</div>
				<div class="contrnt__item">
					<div class="content__icon"><i class="fa fa-eye" aria-hidden="true"></i></div>
					<div class="content__number">942.3萬</div>
				</div>
			</div>
		</div>

		<div class="card">
			<div class="card__block">
				<div class="card__img">
					<img src="https://source.unsplash.com/random/400x300?sig=5" />
				</div>

				<div class="time__block">
					<div class="time__icon"><i class="fa fa-clock-o" aria-hidden="true"></i></div>
					<div class="time__text">22:00</div>
				</div>
				<div class="card__heart"><i class="fa fa-heart-o" aria-hidden="true"></i></div>
				<div class="video__block">
					<div class="video__icon"><i class="fa fa-youtube-play" aria-hidden="true"></i></div>
					<div class="video__text">第24集</div>
				</div>
			</div>
			<div class="content">
				<div class="content__title">
					<div class="marquee__text">出租女友 第二季</div>
				</div>
				<div class="contrnt__item">
					<div class="content__icon"><i class="fa fa-eye" aria-hidden="true"></i></div>
					<div class="content__number">79.5萬</div>
				</div>
			</div>
		</div>
	</div>
	<div class="break"></div>
</section>

CSS:

.card {
	border-radius: 3px;
	font-size: 14px;
	overflow: hidden;
	box-shadow: 0 3px 4px rgba(0, 0, 0, 0.1), 0 1px 8px rgba(0, 0, 0, 0.05),
		0 2px 20px rgba(0, 0, 0, 0.1);
	cursor: pointer;
}

.card__block {
	position: relative;
	overflow: hidden;
}

.card__img {
	max-height: 95px;
	background-size: cover;
	transition: 0.5s;
}

.card__img:hover {
	transform: scale(1.5);
	transition: 0.5s;
}

.card__heart {
	position: absolute;
	top: 0;
	right: 0;
	margin: 5px;
}

.time__block {
	margin: 5px;
	padding: 4px 8px;
	border-radius: 4px;
	font-size: 12px;
	color: #fff;
	background: rgba(55, 55, 55, 0.9);
	display: flex;
	position: absolute;
	top: 0;
}

.time__icon {
	margin-right: 3px;
}

.fa-heart-o {
	font-size: 1rem;
	font-weight: bold;
	color: #fff;
}

.video__block {
	font-weight: bold;
	margin: 5px;
	color: #fff;
	display: flex;
	align-items: center;
	position: absolute;
	bottom: 0;
}

.video__icon {
	margin-right: 3px;
}

.contentx {
	display: flex;
	justify-content: space-around;
	align-items: center;
	grid-template-columns: auto auto auto;
	padding: 4px 8px;
	vertical-align: middle;
}

.content__title {
	width: 100%;
	overflow: hidden;
	white-space: nowrap;
}

.contrnt__item {
	display: grid;
	grid-template-columns: auto auto;
	gap: 5px;
	align-items: center;
	justify-content: center;
}

.content__icon {
	width: 100%;
	box-sizing: border-box;
}

.content__number {
	white-space: nowrap;
}

.marquee__text {
	animation: slide 7s linear infinite;
}

.marquee__text:hover {
	animation-play-state: paused;
}

@keyframes slide {
	from {
		transform: translateX(100%);
	}
	to {
		transform: translateX(-100%);
	}
}

@media (min-width: 575.98px) {
	.container {
		grid-template-columns: auto auto auto;
		gap: 12px;
		padding: 16px 12px;
	}
	.card__img {
		max-height: 135px;
	}
}

@media (min-width: 767.98px) {
}

@media (min-width: 1199.98px) {
	.container {
		grid-template-columns: auto auto auto auto auto;
		gap: 12px;
		padding: 16px 12px;
	}
	.card__img {
		max-height: 140px;
	}

	.containerx {
		display: grid;
		grid-template-columns: auto auto auto;
		gap: 100px;
		padding: 16px 12px 0;
		max-width: 1200px;
		margin: 30px auto;
	}
}

顯示結果:

https://i.imgur.com/s6nysnR.gif

3.2 About Me

HTML:

<!-- 介紹 gif -->
<section class="section__about">
	<img src="https://i.imgur.com/JJ0ujLl.gif" alt="" />
</section>

<!-- 自介 info -->
<section class="section__info purple">
	<div class="break"></div>
	<h1>About Skrman</h1>
	<p>活在當下,對事物充滿好奇心,總是做得比說的還多。</p>
	<div class="break purplr"></div>
</section>

顯示結果:

https://i.imgur.com/JBYgAsO.gif

3.3 timeline

timeline 主要是用來放經歷相關的資訊。

HTML:

<section class="section__exp purple">
		<div class="break"></div>
		<h1>Experience</h1>
		<div class="break"></div>
		<div class="timeline">
			<div class="container left">
				<div class="content">
					<h2>2022</h2>
					<p>
						Lorem ipsum dolor sit amet, quo ei simul congue exerci, ad nec admodum perfecto
						mnesarchum, vim ea mazim fierent detracto. Ea quis iuvaret expetendis his, te elit
						voluptua dignissim per, habeo iusto primis ea eam.
					</p>
				</div>
			</div>
			<div class="container right">
				<div class="content">
					<h2>2021</h2>
					<p>
						Lorem ipsum dolor sit amet, quo ei simul congue exerci, ad nec admodum perfecto
						mnesarchum, vim ea mazim fierent detracto. Ea quis iuvaret expetendis his, te elit
						voluptua dignissim per, habeo iusto primis ea eam.
					</p>
				</div>
			</div>
			<div class="container left">
				<div class="content">
					<h2>2020</h2>
					<p>
						Lorem ipsum dolor sit amet, quo ei simul congue exerci, ad nec admodum perfecto
						mnesarchum, vim ea mazim fierent detracto. Ea quis iuvaret expetendis his, te elit
						voluptua dignissim per, habeo iusto primis ea eam.
					</p>
				</div>
			</div>
			<div class="container right">
				<div class="content">
					<h2>2019</h2>
					<p>
						Lorem ipsum dolor sit amet, quo ei simul congue exerci, ad nec admodum perfecto
						mnesarchum, vim ea mazim fierent detracto. Ea quis iuvaret expetendis his, te elit
						voluptua dignissim per, habeo iusto primis ea eam.
					</p>
				</div>
			</div>

			<div class="container left">
				<div class="content">
					<h2>2018</h2>
					<p>
						Lorem ipsum dolor sit amet, quo ei simul congue exerci, ad nec admodum perfecto
						mnesarchum, vim ea mazim fierent detracto. Ea quis iuvaret expetendis his, te elit
						voluptua dignissim per, habeo iusto primis ea eam.
					</p>
				</div>
			</div>
			<div class="container right">
				<div class="content">
					<h2>2017</h2>
					<p>
						Lorem ipsum dolor sit amet, quo ei simul congue exerci, ad nec admodum perfecto
						mnesarchum, vim ea mazim fierent detracto. Ea quis iuvaret expetendis his, te elit
						voluptua dignissim per, habeo iusto primis ea eam.
					</p>
				</div>
			</div>
		</div>
		<div class="break purple"></div>
</section>

CSS:

.timeline {
	position: relative;
	max-width: 1200px;
	margin: 0 auto;
}

.timeline::after {
	content: "";
	position: absolute;
	width: 6px;
	background-color: white;
	top: 0;
	bottom: 0;
	left: 50%;
	z-index: 0;
	/* margin-left: -6px; */
}

.timeline .container {
	padding: 10px 40px;
	position: relative;
	background-color: inherit;
	width: 50%;
	animation: 1s linear 1s fade;
}

.timeline .container::after {
	content: "";
	position: absolute;
	width: 25px;
	height: 25px;
	right: -17px;
	background-color: white;
	border: 4px solid #ff9f55;
	top: 15px;
	border-radius: 50%;
	z-index: 999;
	margin: 0;
}

.left {
	right: 25%;
	z-index: 9999;
}

.right {
	left: 25%;
	z-index: 9999;
}

.left::before {
	z-index: 9999;
	content: " ";
	height: 0;
	position: absolute;
	top: 22px;
	width: 0;
	z-index: 1;
	right: 30px;
	border: medium solid white;
	border-width: 10px 0 10px 10px;
	border-color: transparent transparent transparent white;
}

.right::before {
	content: " ";
	height: 0;
	position: absolute;
	top: 22px;
	width: 0;
	z-index: 1;
	left: 30px;
	border: medium solid white;
	border-width: 10px 10px 10px 0;
	border-color: transparent white transparent transparent;
}

.right::after {
	left: -8px;
	z-index: 1;
}

.content {
	padding: 20px 30px;
	background-color: white;
	position: relative;
	border-radius: 6px;
}

@keyframes fade {
	from {
		opacity: 0;
		transform: translateY(50%);
	}
	to {
		opacity: 1;
		transform: translateY(0);
	}
}

@media screen and (max-width: 600px) {
	.timeline::after {
		left: 25px;
	}

	.container {
		width: 100%;
		padding-left: 70px;
		padding-right: 25px;
	}

	.container::before {
		left: 60px;
		border: medium solid white;
		border-width: 10px 10px 10px 0;
		border-color: transparent white transparent transparent;
	}

	.left::after,
	.right::after {
		left: 15px;
	}

	.right {
		left: 0;
	}

	.left {
		right: 0;
	}
}

顯示結果:

https://i.imgur.com/otsiuEE.jpg

3.4 Footer

HTML:

<!-- Footer -->
<footer class="text-center text-lg-start bg-light text-muted">
	<!-- Section: Social media -->
	<section class="d-flex justify-content-center justify-content-lg-between p-4 border-bottom">
		<!-- Right -->
		<div>
			<a href="" class="me-4 text-reset">
				<i class="fa fa-facebook-f"></i>
			</a>
			<a href="" class="me-4 text-reset">
				<i class="fa fa-twitter"></i>
			</a>
			<a href="" class="me-4 text-reset">
				<i class="fa fa-google"></i>
			</a>
			<a href="" class="me-4 text-reset">
				<i class="fa fa-instagram"></i>
			</a>
			<a href="" class="me-4 text-reset">
				<i class="fa fa-linkedin"></i>
			</a>
			<a href="" class="me-4 text-reset">
				<i class="fa fa-github"></i>
			</a>
		</div>
		<!-- Right -->
	</section>
	<!-- Section: Social media -->

	<!-- Section: Links  -->
	<section class="">
		<div class="container text-center text-md-start mt-5">
			<!-- Grid row -->
			<div class="row mt-3">
				<!-- Grid column -->
				<div class="col-md-3 col-lg-4 col-xl-3 mx-auto mb-4">
					<!-- Content -->
					<h6 class="text-uppercase fw-bold mb-4"><i class="fas fa-gem me-3"></i>Company name</h6>
					<p>
						Here you can use rows and columns to organize your footer content. Lorem ipsum dolor sit
						amet, consectetur adipisicing elit.
					</p>
				</div>
				<!-- Grid column -->

				<!-- Grid column -->
				<div class="col-md-2 col-lg-2 col-xl-2 mx-auto mb-4">
					<!-- Links -->
					<h6 class="text-uppercase fw-bold mb-4">Products</h6>
					<p>
						<a href="#!" class="text-reset">Angular</a>
					</p>
					<p>
						<a href="#!" class="text-reset">React</a>
					</p>
					<p>
						<a href="#!" class="text-reset">Vue</a>
					</p>
					<p>
						<a href="#!" class="text-reset">Laravel</a>
					</p>
				</div>
				<!-- Grid column -->

				<!-- Grid column -->
				<div class="col-md-3 col-lg-2 col-xl-2 mx-auto mb-4">
					<!-- Links -->
					<h6 class="text-uppercase fw-bold mb-4">Useful links</h6>
					<p>
						<a href="#!" class="text-reset">Pricing</a>
					</p>
					<p>
						<a href="#!" class="text-reset">Settings</a>
					</p>
					<p>
						<a href="#!" class="text-reset">Orders</a>
					</p>
					<p>
						<a href="#!" class="text-reset">Help</a>
					</p>
				</div>
				<!-- Grid column -->

				<!-- Grid column -->
				<div class="col-md-4 col-lg-3 col-xl-3 mx-auto mb-md-0 mb-4">
					<!-- Links -->
					<h6 class="text-uppercase fw-bold mb-4">Contact</h6>
					<p><i class="fas fa-home me-3"></i> New York, NY 10012, US</p>
					<p>
						<i class="fas fa-envelope me-3"></i>
						info@example.com
					</p>
					<p><i class="fas fa-phone me-3"></i> + 01 234 567 88</p>
					<p><i class="fas fa-print me-3"></i> + 01 234 567 89</p>
				</div>
				<!-- Grid column -->
			</div>
			<!-- Grid row -->
		</div>
	</section>
	<!-- Section: Links  -->

	<!-- Copyright -->
	<div class="text-center p-4" style="background-color: rgba(0, 0, 0, 0.05)">
		© 2022 Copyright:
		<a class="text-reset fw-bold" href="https://tonytw.com/">www.tonytw.com</a>
	</div>
	<!-- Copyright -->
</footer>

Footer 可從這裡取得【2】。

顯示結果:(最終結果)

https://i.imgur.com/LHn3z5s.gif


四、推薦資源

  1. 週末長知識: Parallax Scrolling on Touch Devices

五、結論

原本以為整合只是把之前的東西複製貼上就好了,但實際上並不是那麼的簡單,因為在這個整合的過程中遇到了一些問題,例如, Class 命名污染的問題,使用像是containercontent這種名稱,在 CSS 中呼叫就會出現問題。還有程式碼要合併的問題,比如 RWD 內容要寫在一起(這部分還沒有做優化)。其它麻煩的地方還有像是要自己設計版面、補上文字圖片等等內容,這些都是要需要留意的地方。而本篇的實作主要是把網頁組成的架構先跑了一遍,SPA 網頁的撰寫大概都類似這種流程,熟能生巧。那麽,今天的內容都這邊結束,感謝收看!


六、參考資料

  1. 談談 JavaScript 的 setTimeout 與 setInterval
  2. Bootstrap Footer - examples & tutorial

上一篇
Day 28:置中功能實作
下一篇
Day 30 : 完賽心得(2022 主題競賽)
系列文
從零開始手刻網站,30 天打造我的前端武器庫30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言