本帖子來源:小賢筆記
功能
組件 (Component) 是 Vue.js 最強大的功能之一。組件可以擴展 HTML 元素,封裝可重用的代碼。在較高層面上,組件是自定義元素,Vue.js 的編譯器為它添加特殊功能。在有些情況下,組件也可以表現為用 is 特性進行了擴展的原生 HTML 元素。所有的 Vue 組件同時也都是 Vue 的實例,所以可接受相同的選項對象 (除了一些根級特有的選項) 並提供相同的生命周期鈎子
組件注冊
組件名
組件名應該始終是多個單詞的,根組件 App 除外
這樣做可以避免跟現有的以及未來的 HTML 元素相沖突,因為所有的 HTML 元素名稱都是單個單詞的
單文件組件的文件名應該要么始終是單詞大寫開頭 (PascalCase),要么始終是橫線連接 (kebab-case)
混用文件命名方式有的時候會導致大小寫不敏感的文件系統的問題,這也是橫線連接命名同樣完全可取的原因
- 使用 kebab-case
當使用 kebab-case (短橫線分隔命名) 定義一個組件時,你也必須在引用這個自定義元素時使用 kebab-case,例如 <my-component-name>
Vue.component('my-component-name', { /* ... */ })
- 使用 PascalCase
當使用 PascalCase (駝峰式命名) 定義一個組件時,你在引用這個自定義元素時兩種命名法都可以使用。也就是說 <my-component-name> 和 <MyComponentName> 都是可接受的。注意,盡管如此,直接在 DOM (即非字符串的模板) 中使用時只有 kebab-case 是有效的
Vue.component('MyComponentName', { /* ... */ })
全局注冊
以上方法都屬於全局注冊, 也就是說它們在注冊之后可以用在任何新創建的 Vue 根實例 (new Vue) 的模板中, 比如
- HTML
<divid="app">
<component-a></component-a>
<component-b></component-b>
<component-c></component-c>
</div>
- JS
Vue.component('component-a', { /* ... */ })
Vue.component('component-b', { /* ... */ })
Vue.component('component-c', { /* ... */ })
new Vue({ el: '#app' })
在所有子組件中也是如此,也就是說這三個組件在各自內部也都可以相互使用
局部注冊
如果不需要全局注冊,或者是讓組件使用在其它組件內,可以用選項對象的 components 屬性實現局部注冊, 這里不做詳述
ps:具體參考博客vue由淺入深組件的其他內容
父子組件通信
注: 本節引用歲月如同馬匹 - 簡書
在vue組件通信中其中最常見通信方式就是父子組件之中的通性,而父子組件的設定方式在不同情況下又各有不同。最常見的就是父組件為控制組件子組件為視圖組件。父組件傳遞數據給子組件使用,遇到業務邏輯操作時子組件觸發父組件的自定義事件。無論哪種組織方式父子組件的通信方式都是大同小異
父組件到子組件通訊
父組件到子組件的通訊主要為:子組件接受使用父組件的數據,這里的數據包括屬性和方法(String, Number, Boolean, Object, Array, Function)。vue提倡單項數據流,因此在通常情況下都是父組件傳遞數據給子組件使用,子組件觸發父組件的事件,並傳遞給父組件所需要的參數
通過 props 傳遞數據 (推薦)
父子通訊中最常見的數據傳遞方式就是通過props傳遞數據,就好像方法的傳參一樣,父組件調用子組件並傳入數據,子組件接受到父組件傳遞的數據進行驗證使用
props 可以是數組或對象,用於接收來自父組件的數據。props 可以是簡單的數組,或者使用對象作為替代,對象允許配置高級選項,如類型檢測、自定義校驗和設置默認值
prop 的定義應該盡量詳細,至少需要指定其類型
<!-- 父組件 -->
<template>
<div>
<my-child:parentMessage="parentMessage"></my-child>
</div>
</template>
<script>
import MyChild from'@components/common/MyChild'
exportdefault {
components: {
MyChild
},
data() {
return {
parentMessage: "我是來自父組件的消息"
}
}
}
</script>
<!-- 子組件 -->
<template>
<div>
<span>{{ parentMessage }}</span>
</div>
</template>
<script>
exportdefault {
props: {
parentMessage: {
type: String,
default: '默認顯示的信息'
// require: true // 必填
}
}
}
</script>
//父組件顯示:我是來自父組件的消息。
通過 $on 傳遞父組件方法
通過$on傳遞父組件方法是組件通信中常用的方法傳遞方式。它可以與通過props傳遞方法達到相同的效果。相比於props傳遞function,它更加的直觀和顯示的表現出了調用關系
<!-- 父組件 -->
<template>
<div>
<my-child @childEvent="parentMethod"></my-child>
</div>
</template>
<script>
import MyChild from'@components/common/MyChild'
exportdefault {
components: {
MyChild,
},
data() {
return {
parentMessage: '我是來自父組件的消息',
}
},
methods: {
parentMethod() {
alert(this.parentMessage)
}
}
}
</script>
<!-- 子組件 -->
<template>
<div>
<h3>子組件</h3>
</div>
</template>
<script>
exportdefault{
mounted() {
this.$emit('childEvent')
}
}
</script>
//先彈出一個窗口顯示 我是來自父組件的消息,然后父組件顯示文本是子組件
獲取父組件然后使用父組件中的數據(不推薦)
准確來說這種方式並不屬於數據的傳遞而是一種主動的查找。父組件並沒有主動的傳遞數據給子組件,而是子組件通過與父組件的關聯關系,獲取了父組件的數據。
該方法雖然能實現獲取父組件中的數據但是不推薦這種方式,因為vue提倡單向數據流,只有父組件交給子組件的數據子組件才有使用的權限,不允許子組件私自獲取父組件的數據進行使用。在父與子的關系中子應當是處於一種被動關系
// 此處的this為子組件實例
this.$parent
子組件到父組件通訊
子組件到父組件的通訊主要為父組件如何接受子組件之中的數據。這里的數據包括屬性和方法(String, Number, Boolean, Object, Array, Function)
通過 $emit 傳遞父組件數據 (推薦)
與父組件到子組件通訊中的$on配套使用,可以向父組件中觸發的方法傳遞參數供父組件使用
<!-- 父組件 -->
<template>
<div>
<my-child @childEvent="parentMethod"></my-child>
</div>
</template>
<script>
import MyChild from'@components/common/MyChild'
exportdefault {
components: {
MyChild
},
data() {
return {
parentMessage: '我是來自父組件的消息'
}
},
methods: {
parentMethod({ name, age }) {
console.log(this.parentMessage, name, age)
}
}
}
</script>
<!-- 子組件 -->
<template>
<div>
<h3>子組件</h3>
</div>
</template>
<script>
exportdefault {
mounted() {
this.$emit('childEvent', { name: 'zhangsan', age: 10 })
}
}
</script>
//父組件顯示文本為子組件,控制台輸出:我是來自父組件的消息 zhangsan 10
refs 獲取
可以通過在子組件添加ref屬性,然后可以通過ref屬性名稱獲取到子組件的實例。准確來說這種方式和 this.$parent 一樣並不屬於數據的傳遞而是一種主動的查找。
盡量避免使用這種方式。因為在父子組件通信的過程中。父組件是處於高位是擁有控制權,而子組件在多數情況下應該為純視圖組件,只負責視圖的展示和自身視圖的邏輯操作。對外交互的權利應該由父組件來控制。所以應當由父組件傳遞視圖數據給子組件,子組件負責展示。而子組件的對外交互通過$emit觸發父組件中相應的方法,再由父組件處理相應邏輯
<!-- 父組件 -->
<template>
<div>
<my-child ref="child"></my-child>
</div>
</template>
<script>
import MyChild from'@components/common/MyChild'
exportdefault {
components: {
MyChild
},
mounted() {
console.log(this.$refs['child'].getData());
}
}
</script>
<!-- 子組件 -->
<script>
exportdefault {
methods: {
getData() {
// do something...
}
}
}
</script>
//子組件在getdata函數中傳輸的會顯示在父組件,並且會返回getdata函數
組件樣式修改
參考文章: CSS 作用域
如果你希望 scoped 樣式中的一個選擇器能夠作用得“更深”,例如影響子組件,你可以使用 >>> 操作符:
<style scoped>
.a>>>.b { /* ... */ }
</style>
上述代碼將會編譯成:
.a[data-v-f3f3eg9].b { /* ... */ }
有些像 Sass 之類的預處理器無法正確解析 >>>。這種情況下你可以使用 /deep/ 操作符取而代之——這是一個 >>> 的別名,同樣可以正常工作
<style scoped>
.a /deep/ .b { /* ... */ }
</style>