Vue狀態管理之Bus


一般在項目中,狀態管理都是使用Vue官方提供的Vuex

當在多組件之間共享狀態變得復雜時,使用Vuex,此外也可以使用Bus來進行簡單的狀態管理

1.1 父組件與子組件之間的通信

vue.config.js文件內容

const path = require('path')
const resolve = dir => path.join(__dirname,dir)
const BASE_URL = process.env.NODE_ENV === 'production' ? '/iview-admin':'/'

module.exports = {
    lintOnSave: false,
    baseUrl: BASE_URL,
    chainWebpack:config =>{
        config.resolve.alias
        .set('@',resolve('src'))    // 用 @ 符號來替代 src 這個路徑
        .set('_c',resolve('src/components'))        // 用 _c 來替代 src/components這個目錄
    },
    productionSourceMap:false,       // 打包時不生成 .map文件,減少打包的體積同時加快打包速度
    devServer:{         // 跨域配置,告訴開發服務器將任何沒有匹配到靜態文件的請求都代理到proxy指定的URL
        proxy:'http://localhost:8000'
    }
}

src/components/AInput.vue文件內容

<template>
    <input @input="handleInput" :value="value">
</template>
<script>
export default {
    name:"AInput",
    props:{
        value:{
            type:[String,Number],
            default:''
        }
    },
    methods:{
        handleInput (event){
            const value = event.target.value
            this.$emit('input',value)
        }
    }
}
</script>

src/views/store.vue文件內容

<template>
    <div>
        <a-input v-model="inputValue"></a-input>
        <p>{{inputValue}}</p>
    </div>
</template>

<script>
import AInput from '_c/AInput.vue'      // 引入 AInput組件

export default {
    name:'store',
    data () {
        return {
            inputValue:''
        }
    },
    components:{
        AInput      // 注冊AInput組件,然后就可以使用 AInput組件了
    }
}
</script>

src/router/router.vue文件內容

import Home from '@/views/Home.vue'

export default [
    ...     // 此處省略
    {
        path:'/store',
        component:() => import('@/views/store.vue')
    }
]

瀏覽器打開URL:http://localhost:8080/#/store,顯示效果如下

首先在AInput.vue文件中,為input標簽綁定handleInput事件當input框中的數據改變時就會觸發handleInput事件,input標簽中顯示的數據就是value的值

store.vue文件中,a-input標簽使用v-model進行雙向綁定,v-model是一個語法糖

v-model的效果等同於如下
src/views/store.vue文件內容

<template>
    <div>
        <a-input :value="inputValue" @input="handleInput"></a-input>
        <p>{{inputValue}}</p>
    </div>
</template>

<script>
import AInput from '_c/AInput.vue'

export default {
    name:'store',
    data () {
        return {
            inputValue:''
        }
    },
    components:{
        AInput
    },
    methods:{
        handleInput(val){
            this.inputValue = val
        }
    }
}
</script>

相比於上面的代碼方式,v-model方便很多

vue中,單向數據流通信:

父組件向子組件傳值一定是通過屬性,子組件想修改父組件傳遞的值時,一定要通過事件,把要修改的值以參數的形式通過事件提交給父組件,然后在父組件中綁定事件接收消息知道子組件要修改父組件中的數據,最后就可以在子組件中修改數據了,這就是父子組件之間的通信

1.2 單頁面中多組件(兄弟組件)中的通信

src/components目錄下新建AShow.vue文件
src/components/AShow.vue文件內容

<template>
    <div>
        <p>AShow: {{ content }}</p>
    </div>
</template>
<script>
export default {
    props: {
        content: {
            type: [String, Number],
            default: ''     // content的值默認為空
        }
    }
}
</script>

修改src/components/store.vue文件內容

<template>
    <div>
        <a-input @input="handleInput"></a-input>
        <a-show :content="inputValue"></a-show>
    </div>
</template>
<script>
import AInput from '_c/AInput.vue'      // 引入 AInput組件
import AShow from '_c/AShow.vue'      // 引入 AShow組件

export default {
    name:'store',
    data () {
        return {
            inputValue:''
        }
    },
    components:{
        AInput,      // 注冊AInput組件,然后就可以使用 AInput組件了
        AShow       // 注冊AShow組件
    },
    methods: {
        handleInput(val){
            this.inputValue = val
        }
    }
}
</script>

瀏覽器打開URL: http://localhost:8080/#/store,顯示效果如下

可以看到,在父組件store中給子組件AInput綁定事件handleInput,handleInput觸發之后,把AInput組件中輸入的數據賦值給this.inputValue

最后再把this.inputValue的值傳遞給AShow組件的content屬性,以達到單頁面下多組件傳值的目的。

1.3 使用Bus進行多組件的通信

src/lib目錄下新建'bus.js'文件
src/lib/bus.js文件內容

import Vue from 'vue'
const Bus = new Vue()
export default Bus

src/main.js文件中引入bus.js文件
src/main.js文件內容

import Vue from 'vue'
import App from './App.vue'
import router from './router/index'
import store from './store/index'
import Bus from '@/lib/bus'     // 引入Bus組件

Vue.config.productionTip = false
Vue.prototype.$bus = Bus    // 注冊到vue的根實例里,給vue原生對象上添加bus屬性

new Vue({
    router,
    store,
    render: h => h(App)
}).$mount('#app')

src/views/view1.vue文件內容

<template>
    <div class="div2">
        <button @click="handleClick" name="button">按鈕一</button>
    </div>
</template>
<script>
    export default {
        methods: {
            handleClick() {
                this.$bus.$emit('changeValue', 'hello')  // 把on-click事件提交給 bus
            }
        },
        mounted () {
            console.log(this.$bus)      // 打印出 this.$bus對象
        }
    }
</script>
<style>
    .div2 {
        border: 1px solid green;
    }
</style>

src/views/view2.vue文件內容

<template>
    <div class="div1">
        <p>{{ message }}</p>
    </div>
</template>
<script>
    export default {
        data() {
            return {
                message: ''
            }
        },
        mounted() {
            this.$bus.$on('changeValue', msg => {
                this.message = msg
            })  // 監聽bus的 on-click 事件
        }
    }
</script>
<style>
    .div1 {
        border:1px solid red;
    }
</style>

src/router/router.js文件內容

import Home from '@/views/Home.vue'

export default [
    {
        path:'/named_view',
        components:{
            default: () => import('@/views/child.vue'),
            view1: () => import('@/views/view1.vue'),
            view2: () => import('@/views/view2.vue'),
        }
    }
    ...
]

瀏覽器打開URL: http://localhost:8080/#/named_view,在瀏覽器的調試工具中可以看到打印的this.$bus對象

頁面渲染結果為

點擊頁面上的'按鈕一',效果如下

在上面的例子里,按鈕一所有的綠色框所在就是view1組件,紅色框所在就是view2組件

view1.vue組件中,$emit方法會在當前組件view1上把changeValue事件changeValue是綁定在this.$bus這個vue實例上,然后獲取changeValue事件的返回值'hello'

然后在view2組件中,在this.$bus這個實例上監聽changeValue事件,得到changeValue事件的返回值'hello',然后把返回值賦值給 message,並在p標簽上顯示出來,這樣就實現了不同組件之間的通信。


免責聲明!

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



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