Vue入門系列(五)組件通信

組件內(nèi)通信主要分為兩種:父子組件通信和子組件之間通信。

1.父子組件通信

  • 父組件通過props屬性向子組件傳遞數(shù)據(jù),這點和React一樣。
  • 子組件通過事件emit給父組件發(fā)送消息。
props-events.png

看一個例子:

// 組件A中使用子組件confirmDialog
<template>
...
  <vc-confirmDialog :msgTitle="msgObj.title" :msgBody="msgObj.msg" 
    v-on:cancel="closeDialog" v-on:ok="deleteItem">
  </vc-confirmDialog>
</template>
<script type="es6">
  import confirmDialog from '../widget/confirmDialog.vue';
  export default{
    ...
    components: {
      'vc-confirmDialog': confirmDialog //定義組件標(biāo)簽
    },
}
</script>

//子組件confirmDialog
<script type="es6">
  export default{
  ...
  // 接收父組件的屬性值
  props: {
            msgTitle: {
                type: String,
                default: ''
            },
            msgBody: {
                type: String,
                default: ''
            }
        }
  },
  methods: {
            cancel: function () {
                // 觸發(fā)父組件屬性函數(shù)
                this.$emit('cancel');
            },

            ok: function () {
                // 觸發(fā)父組件屬性函數(shù)
                this.$emit('ok');
            }
        }
  }
</script>

父組件通過屬性綁定方式<vc-confirmDialog :msgTitle="msgObj.title" :msgBody="msgObj.msg" @cancel="closeDialog" @ok="deleteItem"></vc-confirmDialog>傳遞了兩類屬性參數(shù)給子組件:

  1. 數(shù)據(jù)屬性:msgTitlemsgBody是傳遞給子組件的數(shù)據(jù),子組件通過props接收。
  2. 事件屬性:父組件通過@eventName="eventFuc"來定義接收函數(shù),一旦子組件觸發(fā)需要父組件同步更新的事件$emit("eventName"),父組件即會調(diào)用eventFunc,然后更新數(shù)據(jù)。

父組件可以利用ref屬性直接訪問組件實例/DOM對象。這一點,和React一樣。

<vc-confirmDialog :msgTitle="msgObj.title" :msgBody="msgObj.msg"
 @cancel="closeDialog" @ok="deleteItem" ref="dialog"></vc-confirmDialog>
...
//父組件直接調(diào)用子組件方法
this.$refs.dialog.ok();

相比Vue,React父子組件通信無需事件機(jī)制,只需要屬性傳遞即可(參考文章:React入門系列(六)組件間通信)。

2.組件間通信

我們可以定義一個空的Vue實例作為event bus,通過事件廣播emit和事件監(jiān)聽on來傳遞數(shù)據(jù)。

// 數(shù)據(jù)總線bus.js
import Vue from 'vue';
export default new Vue();

// 組件A中觸發(fā)事件
bus.$emit('toggleLogin', false);

// 組件B中接收事件
bus.$on('toggleLoading', (show)=>{
  this.isShowLoading = show;
});

如果是大量組件交叉性復(fù)雜通信,建議用插件Vuex處理。

3.Vuex

Vuex的核心是一個全局store,其為一個容器,包含著應(yīng)用中大部分的狀態(tài)(state)
Vuex 和單純的全局對象有以下兩點不同:

  • Vuex 的狀態(tài)存儲是響應(yīng)式的。當(dāng) Vue 組件從 store 中讀取狀態(tài)的時候,若 store 中的狀態(tài)發(fā)生變化,那么相應(yīng)的組件也會相應(yīng)地得到高效更新。

  • 不能直接改變 store 中的狀態(tài)。改變 store 中的狀態(tài)的唯一途徑就是顯式地提交(commit) mutations。

vuex.png
(1) state

Vuex 使用 單一狀態(tài)樹 —— 用一個對象就包含了全部的應(yīng)用層級狀態(tài)。

這也意味著,每個應(yīng)用將僅僅包含一個 store 實例(可以利用modules把store細(xì)分)。

vue組件內(nèi)調(diào)用:

this.$store.state.count

也可以通過輔助函數(shù)mapState獲取多個狀態(tài)值。

export default {
  computed: mapState({
    count: state => state.count,
    countAliasName: 'count',
    totalCount (state) {
      return state.count + this.localCount
    }
  })
}

如果計算屬性名與state節(jié)點屬性名稱一直,那么,可以通過數(shù)組方式更加便捷的獲取state節(jié)點。
如果mapState的值和其他計算屬性混合使用,那么,利用ES的對象展開運(yùn)算符吧。

computed: {
  //  獲取 store.state.count
  ...mapState(["count"]),
  others
}
(2) Getter

Getter可以認(rèn)為是store上的計算屬性,它的返回值會根據(jù)依賴被緩存起來,只有當(dāng)依賴值發(fā)生了變化,才會被重新計算。

state: {
    todos: [
      { id: 1, text: 'abc', checked: true },
    ]
  },
getters: {
    checkedTodos: state => {
      return state.todos.filter(todo => todo.checked)
    }
  }

組件中使用getter如下:

computed: {
  checkedTodosCount () {
    return this.$store.getters.checkedTodos.length
  }
}

如果組件需要批量使用多個getter函數(shù),那么,可以通過輔助函數(shù)mapGettersgetter混入到computed對象中。

export default {
  computed: {
    ...mapGetters(['checkedTodosCount'])
  }
}
(3) moutation

mutation 非常類似事件:每個 mutation 都有一個字符串的事件類型 (type) 和 一個 回調(diào)函數(shù) (handler)。

  • mutation 必須是同步函數(shù)
  • 提交mutation需要用commit函數(shù)
mutations: {
  //payload就是額外的參數(shù)
  increment (state, payload) {
    state.count += payload.amount;
  }
}
組件內(nèi)觸發(fā)事件:
// 以載荷形式分發(fā)
this.$store.commit('increment',{count: 10}); 或者
// 以對象形式分發(fā)
this.$store.commit({
  type: 'increment',
  count: 10
})

也可以使用輔助函數(shù)mapMutations將多個store.commit映射到method對象上。

export default {
  methods: {
    ...mapMutations([
      'increment', // 等價于`this.$store.commit('increment')`
    ]),
  }
}
(4) actions

與mutations不同之處:

  • Action 提交的是 mutation。
  • Action 可以包含異步操作。
  • 提交Action需要用dispatch函數(shù)
actions: {
  increment ({ commit }) {
    setTimeout(() => {
      commit('increment')
    }, 1000)
  }
}
組件內(nèi)觸發(fā)事件:
this.$store.dispatch('increment');

同樣的,可以利用輔助函數(shù)mapActions將組件的methods 映射為 store.dispatch 調(diào)用。

export default {
  methods: {
    ...mapActions([
      'increment', // 等價于`this.$store.dispatch('increment')`
  }
}
(5) modules

使用單一狀態(tài)樹,導(dǎo)致應(yīng)用的所有狀態(tài)集中到一個很大的對象。但是,當(dāng)應(yīng)用變得很大時,store 對象會變得臃腫不堪。

為了解決以上問題,Vuex 允許將 store 分割到模塊(module)。每個模塊擁有自己的 state,mutation,action。

modules.png
// modules/index.js如下
import knowledge from './knowledge'
import common from './common'
import demo from './demo'
import help from './help'

export default {
  knowledge,
  common,
  demo,
  help
}
// index.js 如下
import modules from "./modules";
export default new Vuex.Store({
  modules,
});
// 組件內(nèi)使用如下
store.state.help
store.state.demo
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容