Vue 之 Component
栏目: JavaScript · 发布时间: 7年前
内容简介:Component 概念為 React 所發明,讓我們可以重複使用 HTML,Vue、Angular 也Vue 2.5.17
Component 概念為 React 所發明,讓我們可以重複使用 HTML,Vue、Angular 也 致敬 React,採用 component ,至此 3 大 Framework 都統一採用 Component-based 架構。
Version
Vue 2.5.17
Architecture
Introduction
Vue Instance 有自己的 data 、 methods 、 computed 、 watch ,但 Vue Instance 只是 HTML 的代言人,讓我們在 JavaScript 控制 HTML,但若要 重複使用 ,就不是那麼方便,這時我們需要的是 Vue Component。
除此之外,Vue Component 也讓我們在開發時實踐 Divide and Conquer 哲學,先將需求切成小小 component,然後一一擊破,最後再將 component 組合起來,如此 component 也更加 單一職責 ,更 容易維護 與 重複使用 。
Global Component
之前我們只會 MVVM 的 Hello World,若改用 Component-based 的寫法呢 ?
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Global Component</title>
</head>
<body>
<div id="app">
<hello-world></hello-world>
</div>
</body>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="HelloWorld.js"></script>
<script src="index.js"></script>
</html>
第 9 行
<hello-world></hello-world>
由原本的 <span>Hello World</span> ,變成自訂的 hello-world tag。
我們會為自己的的 Vue Component 定義自己的 HTML tag
index.js
new Vue({
el: '#app'
});
建立 Vue Instance。
HelloWorld.js
Vue.component('HelloWorld', {
template: '<span>Hello World</span>',
});
定義 HelloWorld component。
使用 Vue Vue.component() 定義 Vue Component。
- 第 1 個參數:string,傳入自訂的 HTML tag 名稱
- 第 2 個參數:object,類似傳入 Vue Instance 的 constructor 參數
Vue Component 的使用,有幾點要注意:
- Vue 規定 Vue Component 一定要定義在 Vue Instance
之前,否則 Life Cycle 在compile HTML階段,會不知道 Vue Component 所自訂的 HTML tag - 自訂的 HTML tag 名稱,無論使用 camelCase,CamelCase,最後 Vue 都會改用 Kebab-case (全小寫,單字間以
-隔開),這是 W3C 所建議,且必須是 2 個單字,避免用一個單字與 HTML 預設 tag 重複 - 關於 Component (HTML tag) 與 JavaScript 檔案命名方式,Vue 官方的 Style Guide :
- CamelCase :
HelloWorld、HelloWorld.js、HelloWorld.vue - kebab-case :
hello-world、hello-world.js、hello-world.vue - Vue CLI 使用 CamelCase
- CamelCase :
Local Component
使用 Vue.component() 所宣告的是 Global Component,也就是每個 Vue Instance 都可使用,若你想定義只有某個 Vue Instance 能使用的 component,則要使用 Local Component。
inex.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Local Component</title>
</head>
<body>
<div id="app">
<hello-world></hello-world>
</div>
</body>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="local_component.js"></script>
</html>
HTML 部分一樣不變使用 <hello-world></hello-world> 。
index.js
new Vue({
el: '#app',
components: {
'HelloWorld': {
template: '<span>Hello World</span>',
}
}
});
在傳入 Vue Instance 的 constructor 參數內,加上 components Property,為 object。
以自訂的 HTML tag hello-world 為 key,將 Vue.component() 第二個參數的 object 為 value。
MVVM vs. Component
目前 Vue Component 的 data 顯示都是寫死的,我們知道 MVVM 的精髓就是 Data Binding,要如何將 MVVM 與 Component-based 兩種架構合而為一呢 ?
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Counter Component</title>
</head>
<body>
<div id="app">
<my-counter></my-counter>
<my-counter></my-counter>
</div>
</body>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="MyCounter.js"></script>
<script src="index.js"></script>
</html>
第 9 行
<my-counter></my-counter>
使用自訂的 <my-counter></my-counter> 。
index.js
new Vue({
el: '#app'
});
建立 Vue Instance。
MyComponent.js
Vue.component('MyCounter', {
template: `
<div>
<span>{{ counter }}</span>
<p></p>
<button @click="add">+1</button>
</div>
`,
data() {
return {
counter: 0,
};
},
methods: {
add() {
this.counter++;
}
}
});
第 2 行
template: `
<div>
<span>{{ counter }}</span>
<p></p>
<button @click="add">+1</button>
</div>
`,
將 HTML Template 宣告在 template property 下。
由於 HTML Template 在實務上會很多行,用普通字串不方便,建議改用 ECMAScript 2015 的 string template,就不必再 字串相加 了
第 9 行
data() {
return {
counter: 0,
};
},
data 部分,由原本 Vue Instance 的 data property 改成 data() function。
改回傳 data object。
14 行
methods: {
add() {
this.counter++;
}
}
對 data 內的 counter 累加。
Q : 為什麼寫成 Vue Component 後,要從 data property 改成 data() function ?
data: {
counter: 0
},
若改成 data property 寫法,Vue 會無法執行,且出現 warning。
在正統 OOP,兩個 component 應該是兩個 instance,而 data 包在 instance 內,因此 Component 間的 data 不會互相影響,也就是 OOP 的 封裝 。
但 Vue 底層並不是採用 OOP 方式,而是共用同一份 component instance,只有 data 是不同份。
這也是為什麼為什麼 Vue 要你改用 data() function,而且是回傳全新對 data object。
只要寫 Vue Component,就一定要改用 data() function,不能使用 data property
使用 Vue Component 時,還有一點值得注意:
- 不可使用 HTML self closing 語法
<div id="app"> <my-counter/> <my-counter/> </div>
這種寫法,Vue 不會出錯,但只有一個 component 能動。
<div id="app"> <my-counter></my-counter> <my-counter></my-counter> </div>
要這樣寫,Vue 才能正常執行。
Component vs. DOM Parser
有時候在使用 Vue Component 時,會發現無法如預期顯示在 Browser 裏。
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>DOM Parse Error</title>
</head>
<body>
<div id="app">
<select>
<my-option></my-option>
</select>
</div>
</body>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="index.js"></script>
<script src="MyOption.js"></script>
</html>
第 9 行
<select> <my-option></my-option> </select>
在 <select></select> 內使用自訂的 <my-option></my-option> Vue Component。
index.js
new Vue({
el: '#app'
});
建立 Vue Instance。
MyOption.js
Vue.component('MyOption', {
template: '<option>Vue</option>',
});
自訂的 MyOption 只包含 <option>Vue</option> 部分。
- Chrome 無法正常顯示
-
<select></select>以下沒有任何<option></option>
這牽涉到各 Browser 的 DOM Parser 如何解析 HTML。
以 Chrome 而言,它認為 <select></select> 下 只應該 是 <option></option> ,其他的 HTML tag 都為非法,因此忽略不使用。
DOM Parser 會因 Browser 而異
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>DOM Parse OK</title>
</head>
<body>
<div id="app">
<my-select></my-select>
</div>
</body>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="MySelect.js"></script>
<script src="index.js"></script>
</html>
由本來的 <my-option></my-option> 改成 <my-select></my-select> 。
index.js
new Vue({
el: '#app'
});
建立 Vue Instance。
MySelect.js
Vue.component('MySelect', {
template: `
<select>
<option>Vue</option>
</select>
`,
});
連 <select> 一起包進 Vue Component,如此 Chrome 就無法干涉 <option> 。
Dynamic Component
先定義好 Vue Component,然後動態切換 component。
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Dynamic Component</title>
</head>
<body>
<div id="app">
<button @click="selectLesson">Lessons</button>
<button @click="selectApply">Apply</button>
<p></p>
<component :is="content"></component>
</div>
</body>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="MyLessons.js"></script>
<script src="MyApply.js"></script>
<script src="index.js"></script>
</html>
12 行
<component :is="content"></component>
使用 Vue 擴充的 <component></component> ,綁定其 is ,當 content 指定什麼 Vue Component 時, <component></component> 就會動態切換該 Vue Component。
並沒有在 HTML 內事先使用特定 Component tag,只使用 <component></component> 保留其動態彈性
index.js
new Vue({
el: '#app',
data: {
content: 'my-lessons'
},
methods: {
selectLesson() {
this.content = 'my-lessons';
},
selectApply() {
this.content = 'my-apply';
}
}
});
第 3 行
data: {
content: 'my-lessons'
},
在 data 內定義 content model,其中預設值 my-lessons 為 component 名稱。
第 6 行
methods: {
selectLesson() {
this.content = 'my-lessons';
},
selectApply() {
this.content = 'my-apply';
}
}
由 method 動態改變 content ,MVVM 會再動態改變 <component></component> 的 :is ,達到動態組件的需求。
MyLessions.js
Vue.component('MyLessons', {
template: `
<ul>
<li>React</li>
<li>Angular</li>
<li>Vue</li>
</ul>
`,
});
定義了 MyLessions component。
MyApply.js
Vue.component('MyApply', {
template: `
<form>
<textarea></textarea>
<p></p>
<button>Submit</button>
</form>
`,
});
定義了 MyApply component。
但這兩個 Vue Component 都沒在 HTML 內被使用,將由 JavaScript 動態指定
Keep-Alive
由於 <component></component> 類似 v-if ,其 Dynamic Component 是藉由 刪除 DOM element,並建立新的 DOM element 的方式,所以原本的 user 輸入的資料,也會一併被刪除。
若要保留原本 user 輸入的資料,就必須搭配 <keep-alive><keep-alive> 。
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Keep Alive</title>
</head>
<body>
<div id="app">
<button @click="selectLesson">Lessons</button>
<button @click="selectApply">Apply</button>
<p></p>
<keep-alive>
<component :is="content"></component>
</keep-alive>
</div>
</body>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="MyLessons.js"></script>
<script src="MyApply.js"></script>
<script src="index.js"></script>
</html>
12 行
<keep-alive> <component :is="content"></component> </keep-alive>
在 <component></component> 外部加上 <keep-alive></keep-alive> ,則 Dynamic Component 內的資料將獲得保留。
JavaScript 的寫法不用改變。
Vue 底層會將 user 的輸入保留,然後切換 component 時,除了建立新的 component 外,還會將 user 原本所輸入的資料也 重新 填回新建立的 component,讓動態切換 component 更方便
Conclusion
- Vue 提供了 Vue Component,讓我們將 HTML 會重複的部分可以使用 component 包起來,方便閱讀,也更方便維護
- MVVM 可以 Component-based 完美結合,但
dataproperty 必須改用datafunction - Component 有時候會違背 Browser 的 DOM Parser,此時必須改變寫法繞過 Browser
- Dynamic Component 讓我們可以根據商業邏輯自行切換 component
- 透過神奇的
<keep-alive></keep-alive>,user 原本的輸入將保留在 component 內
Sample Code
完整的範例可以在我的 GitHub 上找到
Reference
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- Vue 之 Component
- Vue Component 之 Slot
- Vue Component 之 Prop
- Vue Component 之 Mixin
- vue-cli3 项目优化之通过 node 自动生成组件模板 generate View、Component
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
世界是平的(3.0版)
[美] 托马斯·弗里德曼 / 何帆、肖莹莹、郝正非 / 湖南科学技术出版社 / 2008-9 / 58.00元
世界变得平坦,是不是迫使我们跑得更快才能拥有一席之地? 在《世界是平的》中,托马斯·弗里德曼描述了当代世界发生的重大变化。科技和通信领域如闪电般迅速的进步,使全世界的人们可以空前地彼此接近——在印度和中国创造爆炸式增长的财富;挑战我们中的一些人,比他们更快占领地盘。3.0版新增两章,更新了报告和注释方面的内容,这些内容均采自作者考察世界各地特别是整个美国中心地带的见闻,在美国本土,世界的平坦......一起来看看 《世界是平的(3.0版)》 这本书的介绍吧!
CSS 压缩/解压工具
在线压缩/解压 CSS 代码
RGB转16进制工具
RGB HEX 互转工具