該應用場景多用於父子組件之間的通訊。
單向數據流html
全部的 prop 都使得其父子 prop 之間造成了一個單向下行綁定:父級 prop 的更新會向下流動到子組件中,可是反過來則不行。這樣會防止從子組件意外變動父級組件的狀態,從而致使你的應用的數據流向難以理解。vue
額外的,每次父級組件發生變動時,子組件中全部的 prop 都將會刷新爲最新的值。這意味着你不應該在一個子組件內部改變 prop。若是你這樣作了,Vue 會在瀏覽器的控制檯中發出警告。es6
v-bind
(縮寫::
)的方式,將數據傳遞給該子組件props
來接收父組件傳遞的數據this.$emit
觸發當前實例上的事件,附加參數都會傳給監聽器回調v-on
(縮寫:@
)的方式,監聽 this.$emit
觸發的事件,在 methods
中定義監聽器回調方法來獲取數據<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>場景一:父子組件通訊</title> <!-- 開發環境版本,包含了有幫助的命令行警告 --> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> </head> <body> <div id="app"> <!-- 父組件掛載到 #app 元素下 --> <m-self></m-self> </div> </body> <script> // 聲明子組件 Vue.component('m-son', { // 子組件接收父組件經過綁定屬性(v-bind/:)綁定的屬性 // 注意⚠️:通常 props 接收的數據做爲初始化數據 props: { b: { type: String, default: '' } }, // :value="b",而不用 v-model="b" 是由於 vue 中 prop 的使用,形成其父子 prop 之間造成了一個單向下行綁定,父級 prop 的更新會向下流動到子組件中,可是反過來則不行。這樣會防止從子組件意外變動父級組件的狀態,從而致使你的應用的數據流向難以理解。 template: `<div> <input type="text" :value="b" @input="onInput" /> </div>`, methods: { onInput(e) { let data = e.target.value // 子組件中更改了數據,經過 $emit 觸發當前實例上的事件。附加參數都會傳給監聽器回調。 this.$emit('onChangeB', data) } } }) // 聲明父組件,並將父組件掛載到 #app 上 let mSelf = new Vue({ el: '#app', data() { return { a: '將要傳遞給子組件的數據' } }, // 父組件經過 v-bind(/:) 的方式,傳遞數據到子組件 // 經過 v-on(/@) 的方式,監聽子組件中 $emit 觸發的事件 template: `<div> <p>{{a}}</p> <m-son :b="a" @onChangeB="onChange"></m-son> </div>`, methods: { onChange(data) { this.a = data } } }) </script> </html>
$parent
子訪問/綁定父 和 $children
父訪問/綁定子$parent
,父實例,若是當前實例有的話。
$parent
,當前實例的直接子組件。 須要注意$children
並不保證順序,也不是響應式的。若是你發現本身正在嘗試使用$children
來進行數據綁定,考慮使用一個數組配合v-for
來生成子組件,而且使用 Array 做爲真正的來源。
節制地使用 $parent
和 $children
- 它們的主要目的是做爲訪問組件的應急方法。更推薦用 props 和 events 實現父子組件通訊。vuex
$parent
子訪問/綁定父this.$parent
獲取父組件的實例(若是有父組件的話),實例上面固然能夠獲取到其掛載的數據v-model
綁定父組件的數據,利用數據響應式完成子傳父$children
父訪問/綁定子this.$parent
拿到父組件的數據,並賦值給子組件,完成數據初始化v-model
綁定子組件中的數據mounted
掛載後,經過 this.$children
獲取到子組件實例數組,將某一子組件實例賦值給父組件的某個變量,利用對象的特性,實現數據響應式。$parent
子訪問/綁定父<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>場景二:父子組件通訊</title> <!-- 開發環境版本,包含了有幫助的命令行警告 --> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> </head> <body> <div id="app"> <!-- 父組件掛載到 #app 元素下 --> <m-self></m-self> </div> </body> <script> // 聲明子組件 Vue.component('m-son', { // 子組件中,經過 this.$parent 訪問父組件實例 template: `<div> <input type="text" v-model="$parent.a" /> </div>` }) // 聲明父組件,並將父組件掛載到 #app 上 let mSelf = new Vue({ el: '#app', data() { return { a: '將要傳遞給子組件的數據' } }, template: `<div> <p>{{a}}</p> <m-son></m-son> </div>` }) </script> </html>
$children
父訪問/綁定子<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>場景二:父子組件通訊</title> <!-- 開發環境版本,包含了有幫助的命令行警告 --> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> </head> <body> <div id="app"> <!-- 父組件掛載到 #app 元素下 --> <m-self></m-self> </div> </body> <script> // 聲明子組件 Vue.component('m-son', { data() { return { // 子組件中,經過 this.$parent 獲取父組件實例,完成數據初始化 b: this.$parent.a } }, template: `<div> <input type="text" v-model="b" /> </div>` }) // 聲明父組件,並將父組件掛載到 #app 上 let mSelf = new Vue({ el: '#app', data() { return { a: '將要傳遞給子組件的數據', children: null } }, template: `<div> <p>{{children && children.b}}</p> <m-son></m-son> </div>`, mounted() { // 實例掛載後,將子組件實例賦值給父組件中定義的數據 // 注意⚠️:$children 在掛載後纔會取到值,並且不是響應式的。爲了達到響應式的效果,這裏採用從新賦值,利用了對象的特性 this.children = this.$children && this.$children[0] } }) </script> </html>
$root
請參考 $parent
$root
當前組件樹的根 Vue 實例。若是當前實例沒有父實例,此實例將會是其本身。
v-bind="$attrs"
祖傳孫和 v-on="$listeners"
孫傳子$attr
包含了父做用域中不做爲 prop 被識別 (且獲取) 的 attribute 綁定 (class
和style
除外)。當一個組件沒有聲明任何 prop 時,這裏會包含全部父做用域的綁定 (class
和style
除外),而且能夠經過v-bind="$attrs"
傳入內部組件——在建立高級別的組件時很是有用。
$listeners
包含了父做用域中的 (不含.native
修飾器的)v-on
事件監聽器。它能夠經過v-on="$listeners"
傳入內部組件——在建立更高層次的組件時很是有用。
該應用場景可用於更高層次組件之間的通訊。
v-bind="$attrs"
和 v-bind="$attrs"
的寫法,不能採用簡寫。npm
v-bind
(簡寫::
) 的方式來傳遞數據$attrs
,即 v-bind="$attrs"
,獲取父級的綁定屬性$attrs
去獲取祖組件傳遞的數據v-on
(簡寫:@) 的方式來接收孫組件回調數據$listeners
即 v-on="$listeners"
,獲取父級的事件監聽器this.$listeners
獲取祖組件的事件監聽器,在數據改變後,執行該監聽器傳遞數據。或者採用 $emit
去觸發<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>場景三:父子孫子等更高級別組件通訊</title> <!-- 開發環境版本,包含了有幫助的命令行警告 --> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> </head> <body> <div id="app"> <!-- 父組件掛載到 #app 元素下 --> <m-self></m-self> </div> </body> <script> // 聲明曾孫組件 Vue.component('m-great-grandson', { // 孫組件經過 $attrs 獲取祖組件傳遞的數據 template: `<div> <input type="text" :value="$attrs.b" @input="onInput" /> </div>`, methods: { onInput(e) { let data = e.target.value // 孫組件中更改了數據,經過 $emit 觸發當前實例上的事件。附加參數都會傳給監聽器回調。 // this.$emit('onChangeB', data) // 或者經過 $listeners 獲取事件監聽器,執行監聽器 this.$listeners.onChangeB(data) } } }) // 聲明孫組件 Vue.component('m-grandson', { // 每層子組件都綁定 $attrs (v-bind="$attrs"),將數據傳給子組件 // 每層子組件都綁定 $listeners (v-on="$listeners"),將事件監聽器傳給子組件 template: `<div> <m-great-grandson v-bind="$attrs" v-on="$listeners"></m-great-grandson> </div>` }) // 聲明子組件 Vue.component('m-son', { // 每層子組件都綁定 $attrs (v-bind="$attrs"),將數據傳給子組件 // 每層子組件都綁定 $listeners (v-on="$listeners"),將事件監聽器傳給子組件 template: `<div> <m-grandson v-bind="$attrs" v-on="$listeners"></m-grandson> </div>` }) // 聲明父組件,並將父組件掛載到 #app 上 let mSelf = new Vue({ el: '#app', data() { return { a: '將要傳遞給曾孫組件的數據' } }, // 父組件內,經過 v-bind(/:) 綁定屬性 (:b="a")。每層子組件都綁定 $attrs (v-bind="$attrs"),實現數據的祖傳孫 // 父組件內,經過 v-on(/@) 綁定事件 (@onChangeB="onChange")。每層子組件都綁定 $listeners (v-on="$listeners"),實現事件監聽器的祖傳孫 template: `<div> <p>{{a}}</p> <m-son :b="a" @onChangeB="onChange"></m-son> </div>`, methods: { onChange(data) { this.a = data } } }) </script> </html>
經過一個公共的區域,來管理數據。可用於非父子組件通訊。
let bus = new Vue()
bus
,同時開啓事件監聽器。觸發事件後,回調處理參數bus
數據賦值給 b 組件,初始化數據。在數據改變後經過 bus.$emit
觸發事件監聽器,回調數據,完成數據傳遞<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>場景四:非父子組件通訊</title> <!-- 開發環境版本,包含了有幫助的命令行警告 --> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> </head> <body> <div id="app"> <!-- 父組件掛載到 #app 元素下 --> <m-self></m-self> </div> </body> <script> // 中央事件管理 let bus = new Vue() // 聲明子組件 a Vue.component('m-son-a', { data() { return { a: '傳給組件 b 數據' } }, template: `<div> <p>{{a}}</p> </div>`, created() { // 將組件 a 數據賦值給 bus,並開啓事件監聽器。觸發後,回調數據即爲 組件 b 傳遞 bus.a = this.a bus.$on('onChangeA', (data) => { this.a = data }) }, methods: { } }) // 聲明子組件 b Vue.component('m-son-b', { data() { return { b: '' } }, template: `<div> <input type="text" :value="b" @input="onInput" /> </div>`, created() { // 數據初始化 this.b = bus.a }, methods: { onInput(e) { let data = e.target.value // 組件 b 中更改了數據,經過 $emit 觸發自定義事件。附加參數都會傳給監聽器回調。 bus.$emit('onChangeA', data) } } }) // 聲明父組件,並將父組件掛載到 #app 上 let mSelf = new Vue({ el: '#app', template: `<div> <m-son-a></m-son-a> <m-son-b></m-son-b> </div>` }) </script> </html>
共用同一對象,可能會引發一些數據的混亂。不理解的狀況下會形成不是預期的變化。數組
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>場景四:父子/非父子組件通訊</title> <!-- 開發環境版本,包含了有幫助的命令行警告 --> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> </head> <body> <div id="app"> <!-- 父組件掛載到 #app 元素下 --> <m-self></m-self> </div> </body> <script> // 聲明一個公用對象,利用對象的特性完成數據共享。也能夠經過 es6 模塊 導出導入對象。index.js 中 export const data = { a: ''} ,import { data } from './index.js' // 將對象賦值給某個變量,這個變量修改了對象中的屬性,則原對象也會改變(對象是地址引用,引用類型) let data = { a: '傳給組件 b 數據' } // 聲明子組件 a Vue.component('m-son-a', { data() { return { data: {} } }, template: `<div> <p>{{data && data.a}}</p> </div>`, created() { // 初始化數據 this.data = data } }) // 聲明子組件 b Vue.component('m-son-b', { data() { return { data: {} } }, template: `<div> <input type="text" v-model="data.a" /> </div>`, created() { // 數據初始化 this.data = data } }) // 聲明父組件,並將父組件掛載到 #app 上 let mSelf = new Vue({ el: '#app', template: `<div> <m-son-a></m-son-a> <m-son-b></m-son-b> </div>` }) </script> </html>
該應用場景用於父子祖孫組件之間的通訊。
這對選項須要一塊兒使用,以容許一個祖先組件向其全部子孫後代注入一個依賴,不論組件層次有多深,並在起上下游關係成立的時間裏始終生效。瀏覽器
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>場景三:父子孫子等更高級別組件通訊</title> <!-- 開發環境版本,包含了有幫助的命令行警告 --> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> </head> <body> <div id="app"> <!-- 父組件掛載到 #app 元素下 --> <m-self></m-self> </div> </body> <script> // 聲明曾孫組件 Vue.component('m-great-grandson', { // inject 引入 provide 注入的屬性 inject: ['a', 'onChangeB'], // 孫組件經過 inject 獲取祖組件傳遞的數據 template: `<div> <input type="text" :value="a" @input="onInput" /> </div>`, methods: { onInput(e) { let data = e.target.value // 孫組件中更改了數據,經過 $emit 觸發當前實例上的事件。附加參數都會傳給監聽器回調。 // this.$emit('onChangeB', data) // 或者 this.onChangeB(data) } } }) // 聲明孫組件 Vue.component('m-grandson', { template: `<div> <m-great-grandson></m-great-grandson> </div>` }) // 聲明子組件 Vue.component('m-son', { template: `<div> <m-grandson></m-grandson> </div>` }) // 聲明父組件,並將父組件掛載到 #app 上 let mSelf = new Vue({ el: '#app', data() { return { b: '將要傳遞給曾孫組件的數據' } }, // provide 能夠是對象,也能夠是返回一個對象函數,該對象包含可注入的屬性 provide() { return { a: this.b, onChangeB: this.onChange } }, // 父組件內,經過 provide 聲明注入屬性 // 父組件內,經過 v-on(/@) 綁定事件 (@onChangeB="onChange") template: `<div> <p>{{b}}</p> <m-son @onChangeB="onChange" ></m-son> </div>`, methods: { onChange(data) { this.b = data } } }) </script> </html>