補充一個 slot 傳值。html
props
能夠是數組或對象,用於接收來自父組件的數據。vue
// 父組件 List.vue <template> <div> <List-item :str="str" :obj="obj" :arr="arr"></List-item> </div> </template> <script> import ListItem from "./ListItem"; export default { data() { return { str: "給子組件傳值", obj: {msg: "給子組件傳值"}, arr: [1, 2, 3] } }, components: { ListItem } } </script> // 子組件 ListItem.vue <template> <div> <div>{{msg}}</div> <div>{{obj}}</div> <div>{{arr}}</div> </div> </template> <script> export default { props: { msg: String, // props是字符串 obj: Object, // props是對象 arr: Array // props是數組 } } </script>
.sync
修飾符 .sync 是 2.3.0+
新增,它對 props
起到了一種修飾的做用,使用 .sync
進行修飾的 props
意味子組件有修改它的意圖,這種狀況下它只起到一個標註性做用,有它沒它都不會影響邏輯(後文會介紹使用 .sync 的其餘做用)。web
使用 .sync
修改上邊的代碼:vuex
// 父組件 List.vue <template> <!-- 這裏不寫 .sync 也不會影響結果 --> <List-item :title.sync="title" @update:title="updataTitle"></List-item> </template> <script> import ListItem from "./ListItem"; export default { data() { return { title: "我是title", } }, components: { ListItem }, methods: { updataTitle(res) { this.title = res; } } } </script> // 子組件 ListItem.vue <template> <div> <button @click="handleClick">Click me</button> <div>{{title}}</div> </div> </template> <script> export default { props: { title: String, }, methods: { handleClick() { // 子組件向父組件傳值 this.$emit('update:title', '我要父組件更新 title'); } } } </script>
使用.sync
向子組件傳遞 多個props:api
當咱們用一個對象同時設置多個 prop
的時候,也能夠將這個 .sync
修飾符和 v-bind
配合使用:數組
<text-document v-bind.sync="doc"></text-document>
這樣會把 doc
對象中的每個屬性 (如 title) 都做爲一個獨立的 prop
傳進去,而後各自添加用於更新的 `v-on 監聽器。微信
更多介紹,.sync 。網絡
這種方式,從嚴格意思上講不是值的傳遞,而是一種"取"(不推薦直接經過實例進行值的獲取)。app
能夠經過 Vue 的實例屬性 $parent
得到父組件的實例,藉助實例能夠調用父實例中的方法,或者獲取父實例上的屬性,從而達到取值的目的。dom
// 父組件 List.vue ... <script> export default { data() { return { message: "hello children", msg: "hello" } }, methods: { sendMessage() { return this.message; } } } </script> // 子組件 ListItem.vue <template> <div> <div>{{data}}</div> <div>{{msg}}</div> </div> </template> <script> export default { data() { return { data: "", msg: "" } }, mounted() { this.data = this.$parent.sendMessage(); // 調用父實例中的方法 this.msg = this.$parent.msg; // 獲取父實例中的屬性 } } </script>
拓展
子組件調用父組件中的方法:
$parent
獲取父實例 this.$parent.event
。props
傳遞方法。$emit
監聽父組件中的方法 this.$emit("envnt")
。$emit
發送一個自定義事件,事件名稱是一個字符串。v-on
綁定子組件發送的自定義事件。// 父組件 List.vue <template> <div> <!-- 監聽自定義事件 --> <List-item v-on:welcome="getWelcome"></List-item> </div> </template> <script> import ListItem from "./List-item"; export default { components: { ListItem }, methods: { getWelcome(data) { alert(data) } } } </script> // 子組件 ListItem.vue <template> <button @click="handleClick">Click me</button> </template> <script> export default { methods: { handleClick() { // 使用 $emit 發送自定義事件 welcome this.$emit('welcome', 'hello'); } } } </script>
此方式同 $parent
,這裏就不進行介紹了。
儘管存在 prop
和事件,有的時候你仍可能須要在 JavaScript 裏直接訪問一個子組件。爲了達到這個目的,能夠經過 ref
特性爲這個子組件賦予一個 ID 引用。
<template> <div> <List-item ref="item" :title="title"></List-item> <div>{{data}}</div> </div> </template> <script> import ListItem from "./List-item"; export default { data() { return { title: "我是title", data: "" } }, components: { ListItem }, mounted() { this.data = this.$refs.item.message; } } </script>
非父子組件傳值,可使用一個空的 Vue 實例做爲中央事件總線,結合實例方法 $on
和 $emit
完成傳值操做。
Bus 的定義方式有如下三種:
將 Bus
抽離出來,組件有須要時進行引入。
// Bus.js import Vue from 'vue' const Bus = new Vue() export default Bus
將 Bus
掛載到 Vue 根實例的原型上。
import Vue from 'vue' Vue.prototype.$bus = new Vue();
將 Bus
注入到 Vue 根對象上。
import Vue from 'vue' const Bus = new Vue() new Vue({ el:'#app', data: { Bus } })
下面案例中的 Bus
掛載在 Vue 原型上:
// 組件1 使用 $emit 向外部發布自定義事件 <template> <button @click="handleClick"> Send Message</button> </template> <script> export default { data() { return { message: "給兄弟組件傳值", } }, methods: { handleClick() { this.$Bus.$emit("sendMessage", this.message) } } } </script> // 組件2 使用 $on 訂閱外部發布的事件 <template> <div> {{data}} </div> </template> <script> export default { data() { return { data: "", } }, mounted() { this.$Bus.$on("sendMessage", data => { this.data = data; }) } } </script>
注意:註冊的 Bus
要在組件銷燬時卸載,不然會屢次掛載,形成觸發一次但多個響應的狀況。
beforeDestroy () { this.$Bus.$off('sendMessage', this.message); }
Vuex 是一個專爲 Vue.js 應用程序開發的狀態管理模式。它採用集中式存儲管理應用的全部組件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化。
圖片引用自網絡:
Vuex 的具體使用。
不是方法的方法:
A
經過事件 $emit
傳值傳給父組件。props
傳值給子組件 B
。provide
選項容許咱們指定咱們想要提供給後代組件的數據/方法。
provide: function () { return { getMap: this.getMap } }
而後在任何後代組件裏,咱們均可以使用 inject
選項來接收指定的咱們想要添加在這個實例上的屬性:
inject: ['getMap']
provide
和 inject
主要爲高階插件/組件庫提供用例。並不推薦直接用於應用程序代碼中。
// 父級組件提供 'foo' var Provider = { provide: { foo: 'bar' }, // ... } // 子組件注入 'foo' var Child = { inject: ['foo'], created () { console.log(this.foo) // => "bar" } // ... }
然而,依賴注入仍是有負面影響的。它將你應用程序中的組件與它們當前的組織方式耦合起來,使重構變得更加困難。同時所提供的屬性是非響應式的。這是出於設計的考慮,由於使用它們來建立一箇中心化規模化的數據跟使用 $root 作這件事都是不夠好的。若是你想要共享的這個屬性是你的應用特有的,而不是通用化的,或者若是你想在祖先組件中更新所提供的數據,那麼這意味着你可能須要換用一個像 Vuex 這樣真正的狀態管理方案了。
這個兩個屬性是 2.4
新增的特性。
$attrs:
官網介紹的很累贅,暫且理解爲非 props
屬性集合。更多介紹。
當一個組件中沒有聲明任何 prop 時,this.$attrs
能夠獲取到全部父做用域的屬性綁定 (class 和 style 除外),而且能夠經過 v-bind="$attrs"
傳給其內部組件 —— 在建立高級別的組件時很是有用。
inheritAttrs:
控制元素屬性是否顯示在 dom 上,默認值爲 true
。
默認狀況下父做用域的不被認做 props 的特性綁定 (attribute bindings) 將會「回退」且做爲普通的 HTML 特性應用在子組件的根元素上。當撰寫包裹一個目標元素或另外一個組件的組件時,這可能不會老是符合預期行爲。經過設置 inheritAttrs 到 false,這些默認行爲將會被去掉。而經過 (一樣是 2.4 新增的) 實例屬性 $attrs 可讓這些特性生效,且能夠經過 v-bind 顯性的綁定到非根元素上。
祖先組件:
<template> <div> <List-item :title="title" :message="message"></List-item> </div> </template> <script> import ListItem from "./List-item"; export default { data() { return { title: "我是title", message: "傳給後代" } }, components: { ListItem } } </script>
父組件:
<template> <div> <h1>{{title}}</h1> <h2>{{$attrs.message}}</h2> <!-- 經過 v-bind="$attrs" 傳入後代組件--> <ListItem2 v-bind='$attrs'></ListItem2> </div> </template> <script> import ListItem2 from './List-item2' export default { props: { title: String }, components: { ListItem2 }, // 默認爲 true,若是傳入的屬性子組件沒有 prop 接受,就會以字符串的形式做爲標籤的屬性存在 <div message="傳給後代"></div> // 設爲 false,在 dom 中就看不到這些屬性 <div>...</div> inheritAttrs: false } </script>
後代組件:
<template> <div> {{$attrs.message}} </div> </template> <script> export default { mounted() { console.log(this.$attrs) // {message: "傳給後代"} } } </script>
渲染出來的結果爲:
在實際項目中確實有遇到插槽後備內容
動態顯示的狀況,因此這裏要補充一下插槽 後備內容
是如何與子組件進行通訊的。
插槽後備內容是指:寫在父組件中,包含在子組件標籤裏的,與子組件中的 slot
對應。
<template> <child-component> 我是插槽的後備內容 </child-component> </template>
好比這裏有一個含有 slot
的 current-user
組件,它的模版結構是這樣的:
<!-- 子組件 current-user.vue --> <template> <div> <div>current-user組件</div> <slot>插槽裏默認顯示:{{user.firstName}}</slot> </div> </template> <script> export default { data() { return { user: { firstName: "zhao", lastName: "xinglei" } } } } </script>
它的父組件是這樣的:
<!-- 父組件 Users.vue --> <template> <div> <div>我是Users組件</div> <current-user> 我是插槽裏的後備內容: {{user.lastName}}(我想顯示爲子組件中 user.lastName ) </current-user> </div> </template> <script> import CurrentUser from './Current-User.vue' export default { components: { CurrentUser } } </script>
咱們看到,在父組件 Users
中,爲子組件 current-user
提供的後備內容中,想要顯示子組件定義的 user.firstName
是不能作到的。
官網中提供一個指令 v-slot,它與 props
結合使用從而達到插槽後備內容與子組件通訊的目的。
咱們首先須要在子組件的 slot
中傳遞一個 props
(這個props
叫作插槽props),這裏咱們起名叫 user
:
<!-- 子組件 current-user.vue --> <template> <div> <div>current-user組件</div> <slot :user="user"> 插槽裏默認顯示:{{user.firstName}} </slot> </div> </template>
在父組件中,包含插槽後備內容的子組件標籤上咱們綁定一個 v-slot
指令,像這樣:
<template> <div> <div>我是Users組件</div> <!-- slotProps裏的內容就是子組件傳遞過來的 props --> <!-- "user": { "firstName": "zhao", "lastName": "xinglei" } --> <current-user v-slot="slotProps"> {{slotProps}} </current-user> </div> </template>
最後渲染出來的結果爲:
官網給這種插槽起名叫作做用域插槽
,更多瞭解。
1. 組件之間傳值無非就是經過屬性、事件和操做 Vue 實例進行的。 2. 操做實例進行組件件通訊,實例屬性 $root、$parent、$children 分別對應了根實例、父實例、子實例。 3 ref 子組件引用,在操做表單元素時會應用的到。 4. Vuex 是一個專爲 Vue.js 應用程序開發的狀態管理模式,簡單的應用不要使用 Vuex。 5. Vue.observable() 讓一個對象可響應,能夠做爲最小化的跨組件狀態存儲器(本文未提到)。