1、安裝element
npm i element-ui -S
2、引入
在main.js寫入一下內容
import Vue from 'vue'; import ElementUI from 'element-ui'; import 'element-ui/lib/theme-chalk/index.css'; import App from './App.vue'; Vue.use(ElementUI); new Vue({ el: '#app', render: h => h(App) });
3、按需引入
借助 babel-plugin-component,我們可以只引入需要的組件,以達到減小項目體積的目的。
首先,安裝 babel-plugin-component:
npm install babel-plugin-component -D
然后,將 .babelrc 修改為:
{ "presets": [["es2015", { "modules": false }]], "plugins": [ [ "component", { "libraryName": "element-ui", "styleLibraryName": "theme-chalk" } ] ] }
4.main.js文件
// The Vue build version to load with the `import` command // (runtime-only or standalone) has been set in webpack.base.conf with an alias. import Vue from 'vue'; import App from './App'; import 'element-ui/lib/theme-chalk/index.css'; import router from './router'; import ElementUI from 'element-ui'; Vue.config.productionTip = false Vue.use(ElementUI) /* eslint-disable no-new */ new Vue({ el: '#app', router, components: { App }, template: '<App/>' })
app.vue(添加導航條,及頁面布局)
<template> <el-container> <el-header> <el-menu :default-active="activeIndex" class="el-menu-demo" mode="horizontal" @select="handleSelect"> <el-menu-item index="1">項目搜索</el-menu-item> <el-menu-item index="2">簡介</el-menu-item> <el-menu-item index="3">消息中心</el-menu-item> <el-menu-item index="4"><a href="https://www.ele.me" target="_blank">訂單管理</a></el-menu-item> </el-menu> </el-header> <el-main>Main</el-main> <el-footer>Footer</el-footer> </el-container> </template> <script> export default{ name:'App', data(){ return{ msg:'vue', activeIndex:"1", // activeIndex2:"1", }; }, methods:{ handleSelect(key,keyPath){ console.log(key,keyPath) } } } </script> <style scoped> .el-header, .el-footer { background-color: #B3C0D1; color: #333; text-align: center; line-height: 60px; } .el-main { background-color: #E9EEF3; color: #333; text-align: center; line-height: 160px; } </style>
構建父子組件通訊
父子組件是單向數據流的,父級prop的更新會向下流動到子組件中,但反過來則不行。
注意:每次父級組件發生更新時,子組件中所有的prop都將會刷新為最新的值。
表明不應該在一個子組件內部改變prop。否則會報錯
組件基礎
因為組件是可復用的 Vue 實例,所以它們與 new Vue
接收相同的選項,
例如 data
、computed
、watch
、methods
以及生命周期鈎子等。僅有的例外是像 el
這樣根實例特有的選項。
組件復用
你可以將組件進行任意次數的
復用:
<div id="components-demo"> <button-counter></button-counter> <button-counter></button-counter> <button-counter></button-counter> </div>
注意當點擊按鈕時,每個組件都會各自獨立維護它的 count
。因為你每用一次組件,就會有一個它的新實例被創建
data
必須是一個函數
當我們定義這個 <button-counter>
組件時,你可能會發現它的 data
並不是像這樣直接提供一個對象:
data: { count: 0 }
而是:一個組件的 data
選項必須是一個函數,因此每個實例可以維護一份被返回對象的獨立的拷貝:
data: function () { return { count: 0 } }
組件的組織
通常一個應用會以一棵嵌套的組件樹的形式來組織:
例如:可能會有頁頭、側邊欄、內容區等組件,每個組件又包含了其它的像導航鏈接、博文之類的組件。
為了能在模板中使用,這些組件必須先注冊以便 Vue 能夠識別。這里有兩種組件的注冊類型:全局注冊和局部注冊。
至此,我們的組件都只是通過 Vue.component
全局注冊的:
Vue.component('my-component-name', { // ... options ... })
全局注冊的組件可以用在其被注冊之后的任何 (通過 new Vue
) 新創建的 Vue 根實例,也包括其組件樹中的所有子組件的模板中。
優先級 A 的規則:必要的 (規避錯誤)
組件名規范
*組件名為多個單詞,根組件App除外。
好處:這樣做可以避免跟現有的以及未來的 HTML 元素相沖突,因為所有的 HTML 元素名稱都是單個單詞的。
例如:
好: Vue.component('todo-item', { // ... }) export default { name: 'TodoItem', // ... }
反例:
Vue.component('todo', {
// ...
})
export default {
name: 'Todo',
// ...
}
組件數據
組件數據data必須是一個函數
當在組件中使用 data
屬性的時候 (除了 new Vue
外的任何地方),它的值必須是返回一個對象的函數。
原因:
當 data 的值是一個對象時,它會在這個組件的所有實例之間共享。想象一下,假如一個 TodoList
組件的數據是這樣的: data: { listTitle: '', todos: [] } 我們可能希望重用這個組件,允許用戶維護多個列表 (比如分為購物、心願單、日常事務等)。
這時就會產生問題。因為每個組件的實例都引用了相同的數據對象,更改其中一個列表的標題就會改變其它
每一個列表的標題。增刪改一個待辦事項的時候也是如此。 取而代之的是,我們希望每個組件實例都管理其自己的數據。為了做到這一點,每個實例必須生成一個獨立的數據對象。在 JavaScript 中,在一個函數中返回這個對象就可以了: data: function () { return { listTitle: '', todos: [] } }
樣本 反例 Vue.component('some-comp', { data: { foo: 'bar' } }) export default { data: { foo: 'bar' } } 好例 Vue.component('some-comp', { data: function () { return { foo: 'bar' } } }) // In a .vue file export default { data () { return { foo: 'bar' } } } // 在一個 Vue 的根實例上直接使用對象是可以的, // 因為只存在一個這樣的實例。 new Vue({ data: { foo: 'bar' } })
Prop定義
Prop定義應該盡量詳細
在你提交的代碼中,prop 的定義應該盡量詳細,至少需要指定其類型。
細致的 prop 定義有兩個好處:
它們寫明了組件的 API,所以很容易看懂組件的用法;
在開發環境下,如果向一個組件提供格式不正確的 prop,Vue 將會告警,以幫助你捕獲潛在的錯誤來源。
樣本: 反例: // 這樣做只有開發原型系統時可以接受 props: ['status'] 好例子 props: { status: String } // 更好的做法! props: { status: { type: String, required: true, validator: function (value) { return [ 'syncing', 'synced', 'version-conflict', 'error' ].indexOf(value) !== -1 } } }
為v-for設置鍵值
總是用 key
配合 v-for
。
在組件上總是必須用 key
配合 v-for
,以便維護內部組件及其子樹的狀態。甚至在元素上維護可預測的行為,比如動畫中的對象固化 (object constancy),也是一種好的做法。

假設你有一個待辦事項列表: data: function () { return { todos: [ { id: 1, text: '學習使用 v-for' }, { id: 2, text: '學習使用 key' } ] } } 然后你把它們按照字母順序排序。在更新 DOM 的時候,Vue 將會優化渲染把可能的 DOM 變動降到最低。即可能刪掉第一個待辦事項元素,然后把它重新加回到列表的最末尾。 這里的問題在於,不要刪除仍然會留在 DOM 中的元素。比如你想使用 <transition-group> 給列表加過渡動畫,或想在被渲染元素是 <input> 時保持聚焦。在這些情況下,為每一個項目添加一個唯一的鍵值 (比如 :key="todo.id") 將會讓 Vue 知道如何使行為更容易預測。 根據我們的經驗,最好始終添加一個唯一的鍵值,以便你和你的團隊永遠不必擔心這些極端情況。也在少數對性能有嚴格要求的情況下,為了避免對象固化,你可以刻意做一些非常規的處理。
反例 <ul> <li v-for="todo in todos"> {{ todo.text }} </li> </ul> 好例 <ul> <li v-for="todo in todos" :key="todo.id" > {{ todo.text }} </li> </ul>
避免 v-if
和 v-for
用在一起
永遠不要把 v-if
和 v-for
同時用在同一個元素上。
一般我們在兩種常見的情況下會傾向於這樣做:
-
為了過濾一個列表中的項目 (比如
v-for="user in users" v-if="user.isActive"
)。在這種情形下,請將users
替換為一個計算屬性 (比如activeUsers
),讓其返回過濾后的列表。 -
為了避免渲染本應該被隱藏的列表 (比如
v-for="user in users" v-if="shouldShowUsers"
)。這種情形下,請將v-if
移動至容器元素上 (比如ul
,ol
)。

當 Vue 處理指令時,v-for 比 v-if 具有更高的優先級,所以這個模板: <ul> <li v-for="user in users" v-if="user.isActive" :key="user.id" > {{ user.name }} </li> </ul> 將會經過如下運算: this.users.map(function (user) { if (user.isActive) { return user.name } }) 因此哪怕我們只渲染出一小部分用戶的元素,也得在每次重渲染的時候遍歷整個列表,不論活躍用戶是否發生了變化。 通過將其更換為在如下的一個計算屬性上遍歷: computed: { activeUsers: function () { return this.users.filter(function (user) { return user.isActive }) } } <ul> <li v-for="user in activeUsers" :key="user.id" > {{ user.name }} </li> </ul> 我們將會獲得如下好處: 過濾后的列表只會在 users 數組發生相關變化時才被重新運算,過濾更高效。 使用 v-for="user in activeUsers" 之后,我們在渲染的時候只遍歷活躍用戶,渲染更高效。 解藕渲染層的邏輯,可維護性 (對邏輯的更改和擴展) 更強。 為了獲得同樣的好處,我們也可以把: <ul> <li v-for="user in users" v-if="shouldShowUsers" :key="user.id" > {{ user.name }} </li> </ul> 更新為: <ul v-if="shouldShowUsers"> <li v-for="user in users" :key="user.id" > {{ user.name }} </li> </ul> 通過將 v-if 移動到容器元素,我們不會再對列表中的每個用戶檢查 shouldShowUsers。取而代之的是,我們只檢查它一次,且不會在 shouldShowUsers 為否的時候運算 v-for。
樣例: 反例: <ul> <li v-for="user in users" v-if="user.isActive" :key="user.id" > {{ user.name }} </li> </ul> <ul> <li v-for="user in users" v-if="shouldShowUsers" :key="user.id" > {{ user.name }} </li> </ul> 好例: <ul> <li v-for="user in activeUsers" :key="user.id" > {{ user.name }} </li> </ul> <ul v-if="shouldShowUsers"> <li v-for="user in users" :key="user.id" > {{ user.name }} </li> </ul>
為組件樣式設置作用域(scoped)
對於應用來說,頂級 App
組件和布局組件中的樣式可以是全局的,但是其它所有組件都應該是有作用域的。
這條規則只和單文件組件有關。你不一定要使用 scoped
特性。設置作用域也可以通過 CSS Modules,
那是一個基於 class 的類似 BEM 的策略,當然你也可以使用其它的庫或約定。
不管怎樣,對於組件庫,我們應該更傾向於選用基於 class 的策略而不是 scoped
特性。
這讓覆寫內部樣式更容易:使用了常人可理解的 class 名稱且沒有太高的選擇器優先級,而且不太會導致沖突。
詳解: 如果你和其他開發者一起開發一個大型工程,或有時引入三方 HTML/CSS (比如來自 Auth0),
設置一致的作用域會確保你的樣式只會運用在它們想要作用的組件上。 不止要使用 scoped 特性,使用唯一的 class 名可以幫你確保那些三方庫的 CSS 不會運用在你自己的 HTML 上。
比如許多工程都使用了 button、btn 或 icon class 名,所以即便你不使用類似 BEM 的策略,
添加一個 app 專屬或組件專屬的前綴 (比如 ButtonClose-icon) 也可以提供很多保護。
樣例: 反例: <template> <button class="btn btn-close">X</button> </template> <style> .btn-close { background-color: red; } </style> ------------------------------------------------------------------------
好例
1 <template> <button class="button button-close">X</button> </template> <!-- 使用 `scoped` 特性 --> <style scoped> .button { border: none; border-radius: 2px; } .button-close { background-color: red; } </style>
2 <template> <button :class="[$style.button, $style.buttonClose]">X</button> </template> <!-- 使用 CSS Modules --> <style module> .button { border: none; border-radius: 2px; } .buttonClose { background-color: red; } </style>
3 <template> <button class="c-Button c-Button--close">X</button> </template> <!-- 使用 BEM 約定 --> <style> .c-Button { border: none; border-radius: 2px; } .c-Button--close { background-color: red; } </style>
私有屬性名($_)
在插件、混入等擴展中始終為自定義的私有屬性使用 $_
前綴。
並附帶一個命名空間以回避和其它作者的沖突 (比如 $_yourPluginName_
)。
詳解:
Vue 使用 _ 前綴來定義其自身的私有屬性,所以使用相同的前綴 (比如 _update) 有覆寫實例屬性的風險。
即便你檢查確認 Vue 當前版本沒有用到這個屬性名,也不能保證和將來的版本沒有沖突。
對於 $ 前綴來說,其在 Vue 生態系統中的目的是暴露給用戶的一個特殊的實例屬性,所以把它用於私有屬性並不合適。
不過,我們推薦把這兩個前綴結合為 $_,作為一個用戶定義的私有屬性的約定,以確保不會和 Vue 自身相沖突。
樣例 反例 var myGreatMixin = { // ... methods: { update: function () { // ... } } } var myGreatMixin = { // ... methods: { _update: function () { // ... } } } var myGreatMixin = { // ... methods: { $update: function () { // ... } } } var myGreatMixin = { // ... methods: { $_update: function () { // ... } } } 好例子 var myGreatMixin = { // ... methods: { $_myGreatMixin_update: function () { // ... } } }
優先級 B 的規則:強烈推薦 (增強可讀性)
組件文件
只要有能夠拼接文件的構建系統,就把每個組件單獨分成文件。
當你需要編輯一個組件或查閱一個組件的用法時,可以更快速的找到它。
反例 Vue.component('TodoList', { // ... }) Vue.component('TodoItem', { // ... }) 好例子 components/ |- TodoList.js |- TodoItem.js components/ |- TodoList.vue |- TodoItem.vue
單文件組件文件的大小寫
單文件組件的文件名應該要么始終是單詞大寫開頭 (PascalCase),要么始終是橫線連接 (kebab-case)。
單詞大寫開頭對於代碼編輯器的自動補全最為友好,因為這使得我們在 JS(X) 和模板中引用組件的方式盡可能的一致。
然而,混用文件命名方式有的時候會導致大小寫不敏感的文件系統的問題,這也是橫線連接命名同樣完全可取的原因。
反例 components/ |- mycomponent.vue components/ |- myComponent.vue 好例子 components/ |- MyComponent.vue components/ |- my-component.vue
基礎組件名
應用特定樣式和約定的基礎組件 (也就是展示類的、無邏輯的或無狀態的組件) 應該全部以一個特定的前綴開頭
,比如 Base
、App
或 V
。
詳解: 這些組件為你的應用奠定了一致的基礎樣式和行為。它們可能只包括: HTML 元素 其它基礎組件 第三方 UI 組件庫 但是它們絕不會包括全局狀態 (比如來自 Vuex store)。 它們的名字通常包含所包裹元素的名字 (比如 BaseButton、BaseTable),除非沒有現成的對應功能的元素 (比如 BaseIcon)。
如果你為特定的上下文構建類似的組件,那它們幾乎總會消費這些組件 (比如 BaseButton 可能會用在 ButtonSubmit 上)。 這樣做的幾個好處: 當你在編輯器中以字母順序排序時,你的應用的基礎組件會全部列在一起,這樣更容易識別。 因為組件名應該始終是多個單詞,所以這樣做可以避免你在包裹簡單組件時隨意選擇前綴 (比如 MyButton、VueButton)。 因為這些組件會被頻繁使用,所以你可能想把它們放到全局而不是在各處分別導入它們。使用相同的前綴可以讓 webpack 這樣工作: var requireComponent = require.context("./src", true, /^Base[A-Z]/) requireComponent.keys().forEach(function (fileName) { var baseComponentConfig = requireComponent(fileName) baseComponentConfig = baseComponentConfig.default || baseComponentConfig var baseComponentName = baseComponentConfig.name || ( fileName .replace(/^.+\//, '') .replace(/\.\w+$/, '') ) Vue.component(baseComponentName, baseComponentConfig) })
樣例 反例 components/ |- MyButton.vue |- VueTable.vue |- Icon.vue 好例子 components/ |- BaseButton.vue |- BaseTable.vue |- BaseIcon.vue components/ |- AppButton.vue |- AppTable.vue |- AppIcon.vue components/ |- VButton.vue |- VTable.vue |- VIcon.vue
單例組件名
只應該擁有單個活躍實例的組件應該以 The
前綴命名,以示其唯一性。
這不意味着組件只可用於一個單頁面,而是每個頁面只使用一次。這些組件永遠不接受任何 prop,因為它們是為你的應用定制的,而不是它們在你的應用中的上下文。如果你發現有必要添加 prop,那就表明這實際上是一個可復用的組件,只是目前在每個頁面里只使用一次。
反例 components/ |- Heading.vue |- MySidebar.vue 好例子 components/ |- TheHeading.vue |- TheSidebar.vue
緊密耦合的組件名
和父組件緊密耦合的子組件應該以父組件名作為前綴命名。
如果一個組件只在某個父組件的場景下有意義,這層關系應該體現在其名字上。
因為編輯器通常會按字母順序組織文件,所以這樣做可以把相關聯的文件排在一起。
詳解 你可以試着通過在其父組件命名的目錄中嵌套子組件以解決這個問題。比如: components/ |- TodoList/ |- Item/ |- index.vue |- Button.vue |- index.vue 或: components/ |- TodoList/ |- Item/ |- Button.vue |- Item.vue |- TodoList.vue 但是這種方式並不推薦,因為這會導致: 許多文件的名字相同,使得在編輯器中快速切換文件變得困難。 過多嵌套的子目錄增加了在編輯器側邊欄中瀏覽組件所花的時間。
樣例
反例 1 components/ |- TodoList.vue |- TodoItem.vue |- TodoButton.vue 2 components/ |- SearchSidebar.vue |- NavigationForSearchSidebar.vue 好例子 1 components/ |- TodoList.vue |- TodoListItem.vue |- TodoListItemButton.vue 2 components/ |- SearchSidebar.vue |- SearchSidebarNavigation.vue
組件名的單詞順序
組件名應該以高級別的 (通常是一般化描述的) 單詞開頭,以描述性的修飾詞結尾。
“為什么我們給組件命名時不多遵從自然語言呢?” 在自然的英文里,形容詞和其它描述語通常都出現在名詞之前,否則需要使用連接詞。比如: Coffee with milk Soup of the day Visitor to the museum 如果你願意,你完全可以在組件名里包含這些連接詞,但是單詞的順序很重要。 同樣要注意在你的應用中所謂的“高級別”是跟語境有關的。比如對於一個帶搜索表單的應用來說,它可能包含這樣的組件: components/ |- ClearSearchButton.vue |- ExcludeFromSearchInput.vue |- LaunchOnStartupCheckbox.vue |- RunSearchButton.vue |- SearchInput.vue |- TermsCheckbox.vue 你可能注意到了,我們很難看出來哪些組件是針對搜索的。現在我們來根據規則給組件重新命名: components/ |- SearchButtonClear.vue |- SearchButtonRun.vue |- SearchInputExcludeGlob.vue |- SearchInputQuery.vue |- SettingsCheckboxLaunchOnStartup.vue |- SettingsCheckboxTerms.vue 因為編輯器通常會按字母順序組織文件,所以現在組件之間的重要關系一目了然。 你可能想換成多級目錄的方式,把所有的搜索組件放到“search”目錄,
把所有的設置組件放到“settings”目錄。我們只推薦在非常大型 (如有 100+ 個組件) 的應用下才考慮這么做,因為: 在多級目錄間找來找去,要比在單個 components 目錄下滾動查找要花費更多的精力。 存在組件重名 (比如存在多個 ButtonDelete 組件) 的時候在編輯器里更難快速定位。 讓重構變得更難,因為為一個移動了的組件更新相關引用時,查找/替換通常並不高效。
自閉合組件
在單文件組件、字符串模板和 JSX 中沒有內容的組件應該是自閉合的——但在 DOM 模板里永遠不要這樣做。
自閉合組件表示它們不僅沒有內容,而且刻意沒有內容。其不同之處就好像書上的一頁白紙對比貼有“本頁有意留白”標簽的白紙。而且沒有了額外的閉合標簽,你的代碼也更簡潔。
不幸的是,HTML 並不支持自閉合的自定義元素——只有官方的“空”元素。所以上述策略僅適用於進入 DOM 之前 Vue 的模板編譯器能夠觸達的地方,然后再產出符合 DOM 規范的 HTML。
反例 <!-- 在單文件組件、字符串模板和 JSX 中 --> <MyComponent></MyComponent> <!-- 在 DOM 模板中 --> <my-component/> 好例子 <!-- 在單文件組件、字符串模板和 JSX 中 --> <MyComponent/> <!-- 在 DOM 模板中 --> <my-component></my-component>
模板中組件名大小寫
對於絕大多數項目來說,在單文件組件和字符串模板中組件名應該總是 PascalCase 的——但是在 DOM 模板中總是 kebab-case 的。
PascalCase 相比 kebab-case 有一些優勢:
- 編輯器可以在模板里自動補全組件名,因為 PascalCase 同樣適用於 JavaScript。
<MyComponent>
視覺上比<my-component>
更能夠和單個單詞的 HTML 元素區別開來,因為前者的不同之處有兩個大寫字母,后者只有一個橫線。- 如果你在模板中使用任何非 Vue 的自定義元素,比如一個 Web Component,PascalCase 確保了你的 Vue 組件在視覺上仍然是易識別的。
不幸的是,由於 HTML 是大小寫不敏感的,在 DOM 模板中必須仍使用 kebab-case。
還請注意,如果你已經是 kebab-case 的重度用戶,那么與 HTML 保持一致的命名約定且在多個項目中保持相同的大小寫規則就可能比上述優勢更為重要了。在這些情況下,在所有的地方都使用 kebab-case 同樣是可以接受的。
反例 <!-- 在單文件組件和字符串模板中 --> <mycomponent/> <!-- 在單文件組件和字符串模板中 --> <myComponent/> <!-- 在 DOM 模板中 --> <MyComponent></MyComponent> 好例子 <!-- 在單文件組件和字符串模板中 --> <MyComponent/> <!-- 在 DOM 模板中 --> <my-component></my-component> 或者 <!-- 在所有地方 --> <my-component></my-component>
JS/JSX 中的組件名大小寫
JS/JSX 中的組件名應該始終是 PascalCase 的,盡管在較為簡單的應用中只使用 Vue.component
進行全局組件注冊時,可以使用 kebab-case 字符串。
詳解 在 JavaScript 中,PascalCase 是類和構造函數 (本質上任何可以產生多份不同實例的東西)
的命名約定。Vue 組件也有多份實例,所以同樣使用 PascalCase 是有意義的。額外的好處是,
在 JSX (和模板) 里使用 PascalCase 使得代碼的讀者更容易分辨 Vue 組件和 HTML 元素。 然而,對於只通過 Vue.component 定義全局組件的應用來說,我們推薦 kebab-case 作為替代。
原因是: 全局組件很少被 JavaScript 引用,所以遵守 JavaScript 的命名約定意義不大。 這些應用往往包含許多 DOM 內的模板,這種情況下是必須使用 kebab-case 的。
樣例 反例 1 Vue.component('myComponent', { // ... }) 2 import myComponent from './MyComponent.vue' 3 export default { name: 'myComponent', // ... } 4 export default { name: 'my-component', // ... } 好例子 5 Vue.component('MyComponent', { // ... }) 6 Vue.component('my-component', { // ... }) 7 import MyComponent from './MyComponent.vue' 8 export default { name: 'MyComponent', // ... }
完整單詞的組件名
組件名應該傾向於完整單詞而不是縮寫。
編輯器中的自動補全已經讓書寫長命名的代價非常之低了,而其帶來的明確性卻是非常寶貴的。不常用的縮寫尤其應該避免。
反例 components/ |- SdSettings.vue |- UProfOpts.vue 好例子 components/ |- StudentDashboardSettings.vue |- UserProfileOptions.vue
Prop名大小寫
在聲明 prop 的時候,其命名應該始終使用 camelCase,而在模板和 JSX 中應該始終使用 kebab-case。
我們單純的遵循每個語言的約定。在 JavaScript 中更自然的是 camelCase。而在 HTML 中則是 kebab-case。
反例 js props: { 'greeting-text': String }
html <WelcomeMessage greetingText="hi"/> 好例子 js props: { greetingText: String }
html <WelcomeMessage greeting-text="hi"/> ***html對大小寫不敏感
多個特性的元素
多個特性的元素應該分多行撰寫,每個特性一行。
在 JavaScript 中,用多行分隔對象的多個屬性是很常見的最佳實踐,因為這樣更易讀。模板和 JSX 值得我們做相同的考慮。
反例 <img src="https://vuejs.org/images/logo.png" alt="Vue Logo"> <MyComponent foo="a" bar="b" baz="c"/> 好例子 <img src="https://vuejs.org/images/logo.png" alt="Vue Logo" > <MyComponent foo="a" bar="b" baz="c" />
模板中的簡單的表達式
組件模板應該只包含簡單的表達式,復雜的表達式則應該重構為計算屬性或方法。
復雜表達式會讓你的模板變得不那么聲明式。我們應該盡量描述應該出現的是什么,而非如何計算那個值。而且計算屬性和方法使得代碼可以重用。
反例 html {{ fullName.split(' ').map(function (word) { return word[0].toUpperCase() + word.slice(1) }).join(' ') }} 好例子 html <!-- 在模板中 --> {{ normalizedFullName }} js // 復雜表達式已經移入一個計算屬性 computed: { normalizedFullName: function () { return this.fullName.split(' ').map(function (word) { return word[0].toUpperCase() + word.slice(1) }).join(' ') } }
簡單的計算屬性
應該把復雜計算屬性分割為盡可能多的更簡單的屬性。
詳解
更簡單、命名得當的計算屬性是這樣的:
易於測試
當每個計算屬性都包含一個非常簡單且很少依賴的表達式時,撰寫測試以確保其正確工作就會更加容易。
易於閱讀
簡化計算屬性要求你為每一個值都起一個描述性的名稱,即便它不可復用。這使得其他開發者
(以及未來的你) 更容易專注在他們關心的代碼上並搞清楚發生了什么。
更好的“擁抱變化”
任何能夠命名的值都可能用在視圖上。舉個例子,我們可能打算展示一個信息,
告訴用戶他們存了多少錢;也可能打算計算稅費,但是可能會分開展現,而不是作為總價的一部分。
小的、專注的計算屬性減少了信息使用時的假設性限制,所以需求變更時也用不着那么多重構了。
樣例 反例 js computed: { price: function () { var basePrice = this.manufactureCost / (1 - this.profitMargin) return ( basePrice - basePrice * (this.discountPercent || 0) ) } } 好例子 js computed: { basePrice: function () { return this.manufactureCost / (1 - this.profitMargin) }, discount: function () { return this.basePrice * (this.discountPercent || 0) }, finalPrice: function () { return this.basePrice - this.discount } }
帶引號的特性值
非空 HTML 特性值應該始終帶引號 (單引號或雙引號,選你 JS 里不用的那個)。
在 HTML 中不帶空格的特性值是可以沒有引號的,但這樣做常常導致帶空格的特征值被回避,導致其可讀性變差。
反例html <input type=text> <AppSidebar :style={width:sidebarWidth+'px'}> 好例子 html <input type="text"> <AppSidebar :style="{ width: sidebarWidth + 'px' }">
指令縮寫
指令縮寫 (用 :
表示 v-bind:
和用 @
表示 v-on:
) 應該要么都用要么都不用。
反例 <input v-bind:value="newTodoText" :placeholder="newTodoInstructions" > <input v-on:input="onInput" @focus="onFocus" > 好例子 <input :value="newTodoText" :placeholder="newTodoInstructions" > <input v-bind:value="newTodoText" v-bind:placeholder="newTodoInstructions" > <input @input="onInput" @focus="onFocus" > <input v-on:input="onInput" v-on:focus="onFocus" >
推薦使用
組件/實例選項中的空行
你可能想在多個屬性之間增加一個空行,特別是在這些選項一屏放不下,需要滾動才能都看到的時候。
當你的組件開始覺得密集或難以閱讀時,在多個屬性之間添加空行可以讓其變得容易。在一些諸如 Vim 的編輯器里,這樣格式化后的選項還能通過鍵盤被快速導航。
props: { value: { type: String, required: true }, focused: { type: Boolean, default: false }, label: String, icon: String }, computed: { formattedValue: function () { // ... }, inputClasses: function () { // ... } }
注意:
在 scoped
樣式中,類選擇器比元素選擇器更好,因為大量使用元素選擇器是很慢的。
反例 <template> <button>X</button> </template> <style scoped> button { background-color: red; } </style> 好例子 <template> <button class="btn btn-close">X</button> </template> <style scoped> .btn-close { background-color: red; } </style>
一個理想的 Vue 應用是 prop 向下傳遞,事件向上傳遞的。
全局組件:
注冊方式:Vue.component(組件名,{方法})
為js代碼,
注意點:全局組件必須寫在Vue實例創建之前,才在該根元素下面生效。
<body> <div id="app"> <my-component></my-component> </div> <div id="app1"> <my-component></my-component> </div> <script> new Vue({ el: "#app" }); Vue.component("my-component", { template: "<h1>我是全局組件</h1>" }); new Vue({ el: "#app1" }) </script> </body>
這樣只會渲染app1根元素下面的,並不會渲染app根下面的,並且會報錯。