一般在項目中,狀態管理都是使用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標簽上顯示出來,這樣就實現了不同組件之間的通信。