Vue2.0 多種組件傳值方法-不過如此的 Vuex

碼文不易啊,轉載請帶上本文連接呀,感謝感謝 https://www.cnblogs.com/echoyya/p/14404397.html

在vue項目中瞭解組件間通信很重要,也是最基礎的面試題,能夠大體總結爲如下幾種狀況和方法:html

1、父向子傳值

父 to 子 :經過動態綁定屬性的方式,子組件在props中去接收,佔爲已用vue

// father.vue
<child :name="name" />

data() {
    return {
        name:'Echoyya',
    }
}
// child.vue
export default {
    props: ['name'],
    mounted() {
        console.log(this.name)  // Echoyya
    }
}

2、子向父傳值 - 1. 事件分發 emit

子 to 父 :經過.emit('事件名稱', 傳遞的參數)事件分發的方式, 父組件當中,調用子組件標籤上綁定自定義事件,其中包含一個參數,即子組件傳遞過來的數據面試

  1. emit 只能接受兩個參數,其他不生效,第一個參數:事件名稱,第二個: 傳遞的數據vuex

  2. 事件分發,不必定要經過點擊事件,也可以使用鉤子函數等數組

  3. 須要傳遞多個參數時,emit第二個參數可選擇數組或是對象promise

// father.vue
<child @send="getChildData" />

methods: {
    getChildData(data){
        console.log('子組件傳遞過來的數據:' + data);
    }
}
// child.vue
<button @click="send">發送數據</button>

export default {
    data() {
        return {
          year:2021
        };
      },
    methods:{
        send(){
          this.$emit('send',this.year)
        }
    }
};

3、子向父傳值 - 2. 父組件動態綁定方法

  1. 除了平時常見的emit 事件分發的方式實現子向父傳值,還有一種不太常見的方式緩存

  2. 在前面有提到過,父向子傳值能夠經過在標籤上動態綁定屬性的方式,一樣也能夠動態綁定方法,在子組件props中接收安全

  3. 在根據實際狀況,在子組件中調用該方法,並傳值,此時父組件執行對應的方法及參數的處理,該參數即是子向父傳遞的數據服務器

// father.vue
<child :fn="getChildData" />

methods: {
    getChildData(data){ // 子組件傳遞過來的數據
        console.log(data); // 子組件 - 2021
    }
}
// child.vue
export default {
  props: ['fn'],
  mounted(){
    this.fn('子組件 - 2021') 
  }
};

4、(主動)父組件主動獲取子組件的數據和方法

  1. 父組件中調用子組件,綁定一個ref屬性app

  2. 主動獲取屬性:this.$refs.ref名稱.屬性

  3. 主動調用方法:this.$refs.ref名稱.方法()

// father.vue
<child :name="name" ref="child" />

mounted() {
    console.log(this.$refs.child.year); // 2021
    this.$refs.child.showName()   // Echoyya:2021
}
// child.vue
export default {
  data(){
    return {
      year:2021
    }
  },
  methods:{
    showName(){
      console.log('Echoyya:'+ this.year);
    }
  }
};

5、(主動)子組件主動獲取父組件的數據和方法

  1. 子組件中調用父組件,使用 this.$parent

  2. 主動獲取屬性:this.$parent.屬性

  3. 主動調用方法:this.$parent.方法(),還能夠向父組件傳遞參數

// father.vue
<div id="app">
  <child />
</div>

<script>
import child from "./components/child";
export default {
  components: {
    child
  },
  data() {
    return {
      name:'Echoyya',
    };
  },
  methods: {
    parentMethod(data){
      // 能夠接收子組件調用時傳遞的參數
      console.log(data);   // 2021
    }
  }
};
</script>
// child.vue
export default {
   mounted(){
      console.log(this.$parent.name);   // Echoyya
      this.$parent.parentMethod(2021);  // 2021
  }
};

6、EventBus 傳值

多層級組件之間相互傳值,或兄弟組件之間傳值,一般使用EventBus,實際上就是 vm,即 Vue 的實例,經過發佈訂閱者模式,實現任意兩組件之間的通信,父子亦可。

  1. 首先建立EventBus文件,導出vm 實例

  2. 在須要通信的兩組件中分別引入該文件

  3. 經過發佈訂閱 .$emit.$on 實現傳值 ,操做的事件名需相同。

// EventBus.js
import Vue from 'vue'
var vm = new Vue()

export default vm
// App.vue
<template>
  <div id="app">
    <bus-one />
    <bus-two />
  </div>
</template>

<script>
import busOne from "./components/bus1";
import busTwo from "./components/bus2";
export default {
  components: {
    busOne,
    busTwo
  }
}
</script>
// bus1.vue
<template>
  <div>
    組件 1 發佈
    <button @click="sendNum">通信發送數據</button>
  </div>
</template>

<script>
import eb from "../EventBus";
export default {
  methods:{
    sendNum(){
      eb.$emit('sendData',111)
    }
  }
};
</script>
// bus2.vue
<template>
  <div>
    組件 2 訂閱 
  </div>
</template>

<script>
import eb from "../EventBus";
export default {
  created(){
    eb.$on('sendData',function(data){
      console.log(data);  // 111
    })
  }
};
</script>

EventBus 內部實現原理

  1. 手動模擬一個 EventBus,實現發佈訂閱的效果,建立一個 myEventBus 文件

  2. 建立一個對象,分別設置發佈、訂閱的事件,以及事件存儲的對象,經過事件訂閱將事件存儲至事件對象中,

  3. 事件發佈時,自動調用事件對象中相同 key 的全部事件

myEventBus.html

<script>
    var eventbus = {
        fnObj:{
            //abc:[fn1,fn2], 能夠屢次訂閱同一個事件,所以每一個 key 對應一個數組
        },
        $on: function (id, fn) {
            if(!this.fnObj[id]){
                this.fnObj[id] = [fn]
            }else{
                this.fnObj[id].push(fn)
            }
        },
        $emit: function (id, data) {
            if(this.fnObj[id]){
                var fnArr = this.fnObj[id]
                // 當事件觸發時,循環執行每一個 key 對應的 全部function
                for(var i = 0;i<fnArr.length;i++){
                    var fn = fnArr[i]
                    fn(data)
                }
            }else{
                console.log('異常,函數不存在')
            }
        }
    }
    eventbus.$on('abc',function(data){
        console.log(1)
    })
    eventbus.$on('abc',function(data){
        console.log(2)
    })
    eventbus.$on('abc',function(data){
        console.log(3)
    })
    eventbus.$on('abc',function(data){
        console.log(4)
    })
    eventbus.$emit('abc','123')
</script>

7、不過如此的 Vuex

  1. Vuex 應用程序開發的 狀態管理模式,集中式管理應用全部組件的狀態,進行組件通信

  2. 安裝插件,引入 Vuex,建立 store 實例,配置到 Vue 實例中

  3. 爲防止狀態,方法聲明等過度重複和冗餘,Vuex 提供了一些輔助函數,mapState,mapGetters,mapMutations,mapActions,可以使用擴展運算符展開,其中:

    • mapState,mapGetters聲明在 computed 中

    • mapMutations,mapActions 聲明在 methods 中

  4. 建立 store 實例,核心屬性:

    • State:一個對象,包含所有的應用狀態。做爲惟一數據源存在。store實例會注入到根組件下的全部子組件

    • Getters:state 中數據派生出一些狀態相似計算屬性,返回值會根據它的依賴被緩存起來,只有依賴發生改變時纔會被從新計算,state 做爲其第一個參數.

    • Mutations:更改 store 中的狀態,store.commit('事件名',payload參數可選)觸發,只作同步操做,

    • Actions:相似於Mutations, 提交的是 mutation,而不是直接變動狀態,能夠包含任意異步操做。this.$store.dispatch分發,異步執行完畢,返回封裝的promise 對象。接受一個與 store 實例具備相同方法和屬性的對象

    • Modules:爲防止 store 對象過於複雜,可將其分割成模塊,每一個模塊都有本身的State,Getters,Mutations,Actions,甚至能夠嵌套子模塊

// main.js
import Vue from 'vue'
import App from './App.vue'
import Vuex from 'vuex'
import numModule from './numModule.js'
Vue.use(Vuex)

var store = new Vuex.Store({
  modules:{
    numModule
  }
})
new Vue({
  store,
  render: h => h(App)
}).$mount('#app')
// numModule.js
export default {
    state: {
        num: 1
    },
    getters: {
        getNum(state) { // 能夠返回一些派生狀態
            return state.num
        }
    },
    mutations: {  
        // 同步修改狀態的函數
        changeNum(state, payload) { 
            state.num += payload.num
        },
        // 異步時,開發工具會遺漏快照,不便於調試(不推薦)
        testAsync(state, data) {
            // 模擬服務器獲取數據
            setTimeout(function () {
                state.num += data
            }, 0)
        }
    },
    actions: {
        // 異步獲取數據,提交給 mutation 進行修改
        incNumByService(store) {
            setTimeout(function () {
                var serviceData = 0.1
                store.commit('changeNum', {
                    num: serviceData
                })
            }, 0)
        }
    }
}
// App.vue
<template>
  <div id="app">
    第一組件
    <p>state:{{$store.state.numModule.num}}</p>
    <!-- getters:方式爲只讀,數據更安全 -->
    <p>getters:{{$store.getters.getNum}}</p>
    <p>MapGetters:{{gn}}</p>

    <button @click="changeNum">mutation同步</button>
    <button @click="testAsync">mutation異步</button>
    <button @click="testActions">action異步</button>
     <Son />
  </div>
</template>

<script>
import { mapGetters } from "vuex";
import Son from "./components/son";
export default {
  components: {
    Son
  },
  methods: {
    changeNum() {
      this.$store.commit({
        type: "changeNum",
        num: 1
      });
      
      //效果同上
      // this.$store.commit("changeNum",{
      //   num: 1
      // });
    },
    testAsync() {
      this.$store.commit("testAsync", 10);
    },
    testActions() {
      // dispatch 異步執行完畢,返回 封裝的promise 對象
      this.$store.dispatch("incNumByService").then(res => {
        alert("dispatch執行完畢");
      });
    }
  },
  computed: {
    //使用對象展開運算符將 getter 混入 computed 對象中
    //若是想將一個 getter 屬性另取一個名字,使用對象形式:
    ...mapGetters({
      gn: "getNum"  // 把 `this.gn` 映射爲 `this.$store.getters.getNum`
    })
  }
};
</script>
// Son.vue
<template>
  <div class="hello">
    第二組件
    <button>state:{{$store.state.numModule.num}}</button>
    <!-- getters:方式爲只讀,數據更安全 -->
    <button>getters:{{$store.getters.getNum}}</button>
    <button @click="clickMe">MapGetters:{{gn}}</button>
  </div>
</template>

<script>
import { mapGetters } from "vuex";
export default {
  computed: {
    ...mapGetters({
      gn: "getNum"
    })
  }
};
</script>
相關文章
相關標籤/搜索