Vue 之 Component
栏目: JavaScript · 发布时间: 6年前
内容简介: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 完美結合,但
data
property 必須改用data
function - 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
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。