Vue組件間數據通信的幾種方式


1 props emit

Vue組件間的響應式通信方式之一,數據通過props以單向數據流的形式從父組件流動到子組件中。
單向流動性會防止子組件意外改變父級組件的狀態,避免應用的數據流向難以理解。
不能處理非父子組件通信的情況

父傳子 props

通過bind指令,父組件數據單向下行流向子組件的props

子傳父 $emit

子組件拋發事件a並傳入數據作為形參,在父組件掛載結點的子組件標簽中監聽a事件.
由於父級模板里的所有內容都是在父級作用域中編譯的,因此a事件的回調函數寫在父組件的methods里面.
methods中拿到形參后用this設置給data數據,這樣就完成子組件到父組件的傳遞

    <div id="app">
        <h1>{{username}}</h1>
        <myinput :value="username" @myinput="inputHandler"></myinput>
    </div>
    <script>
        const myinput = ('my-input', {
            props:['username'],
            template: `<input type='text' :value='username' @input="myemit">`,
            methods:{
                myemit(){
                    console.log(this.$el.value);
                    this.$emit("myinput",this.$el.value);
                }
            }
        });
        var vm = new Vue({
            el: "#app",
            data: {
                username: 'aaa'
            },
            methods: {
                inputHandler(val) {
                    this.username = val;
                }
            },
            components: {
                myinput
            }
        });
    </script>

2 邊界條件

邊界條件主要通過vue的三個實例屬性實現根組件,父組件,子組件之間的數據傳遞

vm.$parent:當前組件的父實例.
vm.$root:組件樹的根實例,如果沒有父實例,vm.$root指向自己.
vm.$refs:注冊過 ref 特性 的所有 DOM 元素和組件實例.

ref 與 $ref
ref用於給子元素或子組件注冊引用信息
$ref是非響應式的,在組件渲染完成之后生效,只能用於父組件拿到子組件實例,不能跨級
任意設置了ref屬性的子組件標簽,都可以在其父組件中通過this.$refs.refvalue拿到對應的實例

<body>
    <div id="app">
        <son ref="getSon"></son>
    </div>
    <script>
        const son = {
            template: `
                <h1>
                    parent-----{{this.$parent.print}}  
                    <br>
                    root-------{{this.$root.print}}
                </h1>
            `,
            data() {
                return {
                    print: "this is son"
                }
            },
        }
        var vm = new Vue({
            el: "#app",
            data: {
                print: 'this is root'
            },
            components: {
                son
            },
            mounted() {
                console.log(this.$refs.getSon.print);
            }
        });
    </script>
</body>

3 依賴注入

作為組件數據傳遞的一種方式,依賴注入允許我們提供給任何后代組件的數據。
只需要在父組件中通過provide函數返回一個數據對象,就可以在后代組件中使用inject注入provide提供的數據,實現組件數據的通信。
依賴注入的特點在於,不局限於父子組件,不論多深的嵌套關系,都可以用它實現組件數據之間的通信。
還有一點值得注意,依賴注入是非響應式的。

<body>
    <div id="app">
        <son></son>
    </div>
    <script>
        const grandson = {
            inject: ['getApple'],
            template: `
                <h2>get -{{getApple}}- from grandfather</h2>
            `
        }
        const son = {
            template: `
                <h1>
                    <grandson></grandson>    
                </h1>
            `,
            components: {
                grandson
            }
        }
        var vm = new Vue({
            el: "#app",
            data: {
                apple: 'a fresh apple'
            },
            provide: function () {
                return {
                    getApple: this.apple
                }
            },
            components: {
                son
            }
        });
    </script>
</body>

4 eventbus 事件總線

使用一個全局的vue實例作為載體,通過這個載體去監聽和拋發事件
將需要傳遞的數據放入$emit函數的參數列表,只要在某一組件中監聽了此事件,就可以通過回調函數拿到此數據。
基於此,通過事件總線,可以實現非父子組件之間的數據通信,如兄弟級、跨級組件通信。

<body>
    <div id="app">
        <son ></son>
        <button @click="giveFoodHandler">拋發事件</button>
    </div>
    <script>
        var eventbus = new Vue();
        const grandson = {
            template: `
                <h2 >get -{{getApple}}- from grandfather</h2>
            `,
            data() {
                return {
                    getApple: ""
                }
            },
            created(){
                eventbus.$on("getFood",(apple)=>{
                    this.getApple = apple;
                })
            }
        }
        const son = {
            template: `
                <h1>
                    <grandson></grandson>    
                </h1>
            `,
            components: {
                grandson
            }
        }
        var vm = new Vue({
            el: "#app",
            data: {
                apple: 'a fresh apple'
            },
            components: {
                son
            },
            methods: {
                giveFoodHandler() {
                    eventbus.$emit("getFood", this.apple);
                }
            }
        });
    </script>
</body>

5 vuex 狀態管理

vuex是vue的狀態管理模式,它的核心是store倉庫對象,它主要用於存放應用的狀態.
在Vuex中,更改狀態的唯一方式是mutation,mutation是同步的,
異步邏輯需要放在action中,但它最后也需要commit到mutation中實現狀態的更改,

使用store的commit與dispatch來進行組件之間的響應式數據狀態管理.

<body>
    <div id="app">
        <counter-btn type="decrement"></counter-btn>
        <counter-span></counter-span>
        <counter-btn type="increment"></counter-btn>
    </div>

    <script>
        Vue.component('counter-btn', {
            props: ['type'],
            template: `
            <button @click='handleClick' >{{btntext}}</button>
            `,
            computed: {
                btntext() {
                    return this.type === 'decrement' ? '-' : '+';
                }
            },
            methods: {
                handleClick() {
                    if (this.type === 'decrement') {
                        store.commit('decrement', { num: 1 });
                        return;
                    }
                    this.$store.dispatch('increment', { num: 1 });
                }
            }
        });

        Vue.component('counter-span', {
            template: `<span>{{$store.state.count}}</span>`,
        });

        var store = new Vuex.Store({
            state: {
                count: 0
            },
            //同步
            mutations: {
                increment(state, obj) {
                    state.count += obj.num;
                },
                decrement(state, obj) {
                    state.count -= obj.num;
                }
            },
            // 異步
            actions: {
                increment(state, obj) {
                    setTimeout(() => store.commit('increment', obj), 0);
                }
            }
        });

        var vm = new Vue({
            el: "#app",
            store
        });
    </script>
</body>

總結

pros emit:

優點:
響應式
單向數據流防止子組件意外改變父級組件的狀態,常用於父子組件通信

缺點:
但是單行向下的bind+props在父子嵌套過多的場景下顯得過於繁瑣。
無法運用在非父子組件通信的場景中

邊界條件

優點:
使用起來較為方便,在子組件標簽上增加ref屬性即可使用

缺點:
在組件渲染完成之后生效
非響應式

依賴注入

優點:
不像props emit用起來那么繁瑣
祖先組件不需要知道那些后代組件使用它提供的屬性,后代組件也不需要知道被注入的屬性來自哪里。
不局限於父子組件,不論多深的嵌套關系,都可以用它實現組件數據之間的通信。

缺點:
但這樣的方式也有一個明顯的缺陷,那就是不支持響應式

事件總線

優點:
eventbus是全局的,意味着可以在任意兩個組件中通過事件的拋發和監聽來傳遞數據。

缺陷:
不支持響應式

vuex

優點:
通過store狀態管理,可以靈活的在父子/非父子/兄弟組件之間進行響應式數據傳遞

缺點
刷新瀏覽器會使得vuex中的state置為初始狀態,考慮結合本地存儲如localstorage進行使用
如果數據不存在跨組件共享,那么也不建議使用vuex
vuex不適合小型項目


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM