將HTML網頁Vue元件化
前一篇簡單的介紹了
元件的基本常識 。這篇我們要來試試看,實際上如何做出元件化的網頁。
第一個例子,我們要透過bootstrap網站上面的html範例,逐步將它改成Vue元件的頁面。
今天我們要練習的畫面,大家可以在這裡取得,下載為html檔案。下載html的方法這裡就不贅述。
https://getbootstrap.com/docs/4.1/examples/
分析頁面
首先,我們先分析一下這個bootstrap的html範例
有頁首、頁尾、且中間主畫面可以分成兩個區塊。
下面區塊可以再分成更細的區塊,總共有六個區塊構成。
我們可以把分析的結果畫成下面的圖表。
網頁可以分割成Header、Footer、主要內容三段。主要內容的部分可以分上下,上面是bigBoard下面是一個個Item組成,總共有六個Item。
再回來對應下載的html原始碼。我們發現:
Header 區塊,從
<header>
開始到
</header>
結束。
Footer 區塊,從
<footer class="text-muted">
開始到
</footer>
結束。
主要內容區塊,從
<main role="main">
開始到
</main>
結束。
主要內容區塊,又可以分成兩段,上半段從
<section class="jumbotron text-center">
開始,到
</section>
結束; 下半段從
<div class="album py-5 bg-light">
開始,到
</div>
結束,裡面有六個Item,每個Item都從。
<div class="col-md-4">
開始,到
</div>
結束。
建立Vue
依照上面的分割方式,我們可以將整個網站分成幾個Vue元件。在分割之前,我們先在頁面上安裝Vue.js。一樣,我們先插入下面兩個部分。
Vue.js的CDN檔案連結
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
建立一個Vue 實例,連結Html上的<div id="app"> </div>
<script>
var app = new Vue({
el: "#app",
})
</script>
當這一切都設定好之後,我們就要來註冊Vue元件了。
依照上面的分析,我們需要建立Head 、Footer、bigBoard、cardCom等元件。
Head 、Footer元件
先從Head 開始,註冊全域元件pageHeader,樣板採用x-template方式,名稱為#header。
Vue.component('pageHeader', {
template: "#header",
data: function () {
return {
title: "ABC",
about: "關於這個網站",
contact: "聯絡我們"
}
}
});
因此,先建立一個x-template 的 script,並且賦予一個header的id。
<script type="text/x-template" id="header">
//樣板
</script>
接著將,Header 區塊(從
<header>
開始到
</header>
結束)貼近去。結果如下:
<script type="text/x-template" id="header">
<header>
<div class="collapse bg-dark" id="navbarHeader">
<div class="container">
<div class="row">
<div class="col-sm-8 col-md-7 py-4">
<h4 class="text-white">{{about}}</h4>
<p class="text-muted">Add some information about the album below, the author, or any other
background context. Make it a few sentences long so folks can pick up some informative
tidbits.
Then, link them off to some social networking sites or contact information.</p>
</div>
<div class="col-sm-4 offset-md-1 py-4">
<h4 class="text-white">{{contact}}</h4>
<ul class="list-unstyled">
<li><a href="#" class="text-white">Follow on Twitter</a></li>
<li><a href="#" class="text-white">Like on Facebook</a></li>
<li><a href="#" class="text-white">Email me</a></li>
</ul>
</div>
</div>
</div>
</div>
<div class="navbar navbar-dark bg-dark shadow-sm">
<div class="container d-flex justify-content-between">
<a href="#" class="navbar-brand d-flex align-items-center">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="none" stroke="currentColor"
stroke-linecap="round" stroke-linejoin="round" stroke-width="2" aria-hidden="true" class="mr-2"
viewBox="0 0 24 24" focusable="false">
<path d="M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z" />
<circle cx="12" cy="13" r="4" /></svg>
<strong>{{title}}</strong>
</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarHeader"
aria-controls="navbarHeader" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
</div>
</div>
</header>
</script>
最後,在Html上的
<div id="app"> </div>
中間,放入
<page-header></page-header>
注意,雖然元件命名為pageHeader(有大小寫),由於在Html中無法分辨大小寫,於是呼叫元件時必須採用<page-header>的方式,也就是 page與header需要小寫,且兩者中間需要一個橫槓(-)才行。
接著,就可以測試看看header是否正常出現在頁面上。
如果沒問題的話,接著就用同樣的方式製作Footer的部分。
註冊Vue元件pageFooter。
Vue.component('pageFooter', {
template: "#footer"
})
建立一個x-template,並且貼上樣板。
<script type="text/x-template" id="footer">
<footer class="text-muted">
<div class="container">
<p class="float-right">
<a href="#">Back to top</a>
</p>
<p>Album example is © Bootstrap, but please download and customize it for yourself!</p>
<p>New to Bootstrap? <a href="https://getbootstrap.com/">Visit the homepage</a> or read our <a href="/docs/4.3/getting-started/introduction/">getting
started guide</a>.</p>
</div>
</footer>
</script>
在Html上的呼叫pageFooter元件。
<page-footer></page-footer>
中間區塊元件
前面Header、Footer部分已經改成Vue元件,我們可以看一下目前的頁面的結構。
<div id="app">
<page-header></page-header>
<!--component pageMain -->
<main role="main">
<!-- component jumbo --><!-- //component jumbo -->
<!-- component container --><!-- //component container -->
</main>
<!--// component pageMain -->
<page-footer></page-footer>
</div>
<main role="main"></main>
中間的部分,我們分兩部分,上半部要放在
<!-- component jumbo --><!-- //component jumbo -->
裡面,下半部則需要放在
<!-- component container --><!-- //component container -->
中間。
上半部跟前面的Header、Footer區塊一樣,先註冊Vue元件jumboCom。
Vue.component('jumboCom', {
template: "#jumbo"
})
接著建立一個x-template,並且貼上樣板。
<script type="text/x-template" id="jumbo">
<section class="jumbotron text-center">
<div class="container">
<h1 class="jumbotron-heading">Album example</h1>
<p class="lead text-muted">Something short and leading about the collection below—its contents, the
creator, etc. Make it short and sweet, but not too short so folks don’t simply skip over it
entirely.</p>
<p>
<a href="#" class="btn btn-primary my-2">Main call to action</a>
<a href="#" class="btn btn-secondary my-2">Secondary action</a>
</p>
</div>
</section>
</script>
最後,在Html上的呼叫jumboCom元件。
<div id="app">
<page-header></page-header>
<!--component pageMain -->
<main role="main">
<!-- component jumbo -->
<jumbo-com></jumbo-com>
<!-- // component jumbo -->
<!-- component container --><!-- //component container -->
</main>
<!--// component pageMain -->
<page-footer></page-footer>
</div>
到這裡為止,剩下最後的一塊,整個畫面就跟Bootstrap上面取得的畫面一樣了。
下半部區塊,需要放在
<!-- component container --><!-- //component container -->
中間。比較單純的做法是,直接在中間放入item的元件。
<!-- component container -->
<div class="album py-5 bg-light">
<div class="container">
<div class="row">
//item元件
</div>
</div>
</div>
<!-- // component container -->
先依照上面說明的方式,先註冊Vue元件cardCom,並建立一個x-template,並且貼上樣板。
Vue.component('cardCom', {
template: "#cardcom",
});
<script type="text/x-template" id="cardcom">
<div class="col-md-4">
<div class="card mb-4 shadow-sm">
<img width="100%" height="225" src="photo.img">
<div class="card-body">
<p class="card-text">文字</p>
<div class="d-flex justify-content-between align-items-center">
<div class="btn-group">
<button type="button" class="btn btn-sm btn-outline-secondary">View</button>
<button type="button" class="btn btn-sm btn-outline-secondary">Edit</button>
</div>
<small class="text-muted">9 mins</small>
</div>
</div>
</div>
</div>
</script>
在Html上的呼叫cardCom元件。
<!-- component container -->
<div class="album py-5 bg-light">
<div class="container">
<div class="row">
<card-com></card-com>
</div>
</div>
</div>
<!-- // component container -->
Item依照數量自動產生
到目前為止,方法都跟上面一樣,你會看到中間下面區會出現一個item。接下來,要讓 item依照資料的數量自動增加,目標是六個item。
先在Vue實體加上data選項,在postsdata 中建立一筆資料。
<script>
var app = new Vue({
el: "#app",
data() {
return {
postsdata: [{
img: "好",
url: "info-center.jpg",
context: ` Lorem ipsum dolor sit amet consectetur adipisicing elit. Magnam aliquam alias vero quas id
voluptates assumenda illum culpa. Soluta repudiandae nemo consequatur facere quibusdam placeat sapiente
reprehenderit quod hic in!`
}]
}
}
})
</script>
在cardCom元件中,加入props。(props在下一篇會說明)
Vue.component('cardCom', {
template: "#cardcom",
props: ["posts"],
});
將原來的
<card-com></card-com>
部分,改成下面的程式碼:
<card-com v-for="(item, key) in postsdata" :key="key" :posts="item"></card-com>
其中,
:posts="item"
地方,綁定元件的資料從Vue實例的data函數中傳入。
而
v-for="(item, key) in postsdata"
的地方會依照data中postsdata內的資料的數量,一組一組顯示出來,目前只放了一組資料。
在x-template的部分也修改成下面程式碼。其中
{{posts.context}}
會將postsdata中的context顯示出來。
而在
<img width="100%" height="225" :src="posts.url" :alt="posts.img">
部分則使用v-bind的方式綁定src與alt兩個 img 的屬性。
<script type="text/x-template" id="cardcom">
<div class="col-md-4">
<div class="card mb-4 shadow-sm">
<img width="100%" height="225" :src="posts.url" :alt="posts.img">
<div class="card-body">
<p class="card-text">
{{posts.context}}
</p>
<div class="d-flex justify-content-between align-items-center">
<div class="btn-group">
<button type="button" class="btn btn-sm btn-outline-secondary">View</button>
<button type="button" class="btn btn-sm btn-outline-secondary">Edit</button>
</div>
<small class="text-muted">9 mins</small>
</div>
</div>
</div>
</div>
</script>
恭喜,第一筆資料已經出現在畫面上了。
接著,你可以再增加5筆資料,如此就大功告成了。
以下是原始碼
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html>
<html lang="zh-tw">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="canonical" href="https://getbootstrap.com/docs/4.3/examples/album/">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css"
integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous" />
<title>將Vue程式碼元件化</title>
<!-- Custom styles for this template -->
<link href="album.css" rel="stylesheet">
</head>
<body>
<div id="app">
<!--component pageHeader -->
<page-header></page-header>
<!--//component pageHeader -->
<!--component pageMain -->
<main role="main">
<!-- component jumbo -->
<jumbo-com></jumbo-com>
<!-- // component jumbo -->
<!-- component container -->
<div class="album py-5 bg-light">
<div class="container">
<div class="row">
<card-com v-for="(item, key) in postsdata" :key="key" :posts="item"></card-com>
<!-- <card-com v-for="(item, key) in postsdata" :key="key" :posts="item"></card-com> -->
</div>
</div>
</div>
<!-- // component container -->
</main>
<!--// component pageMain -->
<!--component pageFooter -->
<page-footer></page-footer>
<!--//component pageFooter -->
</div>
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"
integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous">
</script>
<script src="bootstrap.bundle.min.js"
integrity="sha384-xrRywqdh3PHs8keKZN+8zzc5TX0GRTLCcmivcbNJWm2rs5C8PRhcEn3czEjhAO9o" crossorigin="anonymous">
</script>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<!-- template -->
<script type="text/x-template" id="header">
<header>
<div class="collapse bg-dark" id="navbarHeader">
<div class="container">
<div class="row">
<div class="col-sm-8 col-md-7 py-4">
<h4 class="text-white">{{about}}</h4>
<p class="text-muted">Add some information about the album below, the author, or any other
background context. Make it a few sentences long so folks can pick up some informative
tidbits.
Then, link them off to some social networking sites or contact information.</p>
</div>
<div class="col-sm-4 offset-md-1 py-4">
<h4 class="text-white">{{contact}}</h4>
<ul class="list-unstyled">
<li><a href="#" class="text-white">Follow on Twitter</a></li>
<li><a href="#" class="text-white">Like on Facebook</a></li>
<li><a href="#" class="text-white">Email me</a></li>
</ul>
</div>
</div>
</div>
</div>
<div class="navbar navbar-dark bg-dark shadow-sm">
<div class="container d-flex justify-content-between">
<a href="#" class="navbar-brand d-flex align-items-center">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="none" stroke="currentColor"
stroke-linecap="round" stroke-linejoin="round" stroke-width="2" aria-hidden="true" class="mr-2"
viewBox="0 0 24 24" focusable="false">
<path d="M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z" />
<circle cx="12" cy="13" r="4" /></svg>
<strong>{{title}}</strong>
</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarHeader"
aria-controls="navbarHeader" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
</div>
</div>
</header>
</script>
<script type="text/x-template" id="jumbo">
<section class="jumbotron text-center">
<div class="container">
<h1 class="jumbotron-heading">Album example</h1>
<p class="lead text-muted">Something short and leading about the collection below—its contents, the
creator, etc. Make it short and sweet, but not too short so folks don’t simply skip over it
entirely.</p>
<p>
<a href="#" class="btn btn-primary my-2">Main call to action</a>
<a href="#" class="btn btn-secondary my-2">Secondary action</a>
</p>
</div>
</section>
</script>
<script type="text/x-template" id="footer">
<footer class="text-muted">
<div class="container">
<p class="float-right">
<a href="#">Back to top</a>
</p>
<p>Album example is © Bootstrap, but please download and customize it for yourself!</p>
<p>New to Bootstrap? <a href="https://getbootstrap.com/">Visit the homepage</a> or read our <a href="/docs/4.3/getting-started/introduction/">getting
started guide</a>.</p>
</div>
</footer>
</script>
<script type="text/x-template" id="cardcom">
<div class="col-md-4">
<div class="card mb-4 shadow-sm">
<img width="100%" height="225" :src="posts.url" :alt="posts.img">
<div class="card-body">
<p class="card-text">
{{posts.context}}
</p>
<div class="d-flex justify-content-between align-items-center">
<div class="btn-group">
<button type="button" class="btn btn-sm btn-outline-secondary">View</button>
<button type="button" class="btn btn-sm btn-outline-secondary">Edit</button>
</div>
<small class="text-muted">9 mins</small>
</div>
</div>
</div>
</div>
</script>
<script>
Vue.component('pageHeader', {
template: "#header",
data: function () {
return {
title: "ABC",
about: "關於這個網站",
contact: "聯絡我們"
}
}
});
Vue.component('pageFooter', {
template: "#footer"
})
Vue.component('jumboCom', {
template: "#jumbo"
})
Vue.component('cardCom', {
template: "#cardcom",
props: ["posts"],
});
</script>
<script>
var app = new Vue({
el: "#app",
data() {
return {
postsdata: [{
img: "好",
url: "info-center.jpg",
context: ` Lorem ipsum dolor sit amet consectetur adipisicing elit. Magnam aliquam alias vero quas id
voluptates assumenda illum culpa. Soluta repudiandae nemo consequatur facere quibusdam placeat sapiente
reprehenderit quod hic in!`
},
{
img: "好",
url: "info-center.jpg",
context: ` Lorem ipsum dolor sit amet consectetur adipisicing elit. Magnam aliquam alias vero quas
id
voluptates assumenda illum culpa. Soluta repudiandae nemo consequatur facere quibusdam placeat
sapiente
reprehenderit quod hic in!`
},
{
img: "好",
url: "info-center.jpg",
context: ` Lorem ipsum dolor sit amet consectetur adipisicing elit. Magnam aliquam alias vero quas
id
voluptates assumenda illum culpa. Soluta repudiandae nemo consequatur facere quibusdam placeat
sapiente
reprehenderit quod hic in!`
},
{
img: "好",
url: "info-center.jpg",
context: ` Lorem ipsum dolor sit amet consectetur adipisicing elit. Magnam aliquam alias vero quas
id
voluptates assumenda illum culpa. Soluta repudiandae nemo consequatur facere quibusdam placeat
sapiente
reprehenderit quod hic in!`
}, {
img: "好",
url: "info-center.jpg",
context: ` Lorem ipsum dolor sit amet consectetur adipisicing elit. Magnam aliquam alias vero quas
id
voluptates assumenda illum culpa. Soluta repudiandae nemo consequatur facere quibusdam placeat
sapiente
reprehenderit quod hic in!`
},
{
img: "好",
url: "info-center.jpg",
context: ` Lorem ipsum dolor sit amet consectetur adipisicing elit. Magnam aliquam alias vero
quas id
voluptates assumenda illum culpa. Soluta repudiandae nemo consequatur facere quibusdam placeat
sapiente
reprehenderit quod hic in!`
}
]
}
}
})
</script>
</body>
</html>
留言
張貼留言