对于学vue的小伙伴们而言,父子组件之间的传值想必已经很熟悉了,但是还有一种很常用而且容易出错的通信方式就是:兄弟组件之间的通信(这里以子组件1改变值,子组件2也发生相应改变),为此,我在这里给出3种兄弟组件之间的传值方式。
结论:1.通过:props和$emit来实现
2.新建一个Vue实例,通过自定义事件来触发
3.创建Vuex实例,通过Vuex.store来控制
1.子组件Child1(触发this.$emit('函数名',参数)) --> 父组件props传值 --> 子组件Child2的name改变
启动项目后,初始页面显示如下:
点击子组件Child1的“点击我”按钮后,可以看到name的值都被改变,但是这种传值方式有一个缺点:会导致父组件中的name也被改变。
vue项目文件的核心部分如下:
其中,父组件为Father.vue;子组件1为Child1.vue;子组件2为Child2.vue;
Father.vue
<template>
<div class="hello">
<h1>我是父组件</h1>
<p>name: {{ name }}</p>
<Child1 :name="name" @submitToFather="changeName"/>
<Child2 :name="name" />
</div>
</template>
<script>
import Child1 from './Child1'
import Child2 from './Child2'
export default {
name: 'Father',
data () {
return {
name:"椰子"
}
},
methods:{
changeName(newName){
this.name = newName
}
},
components:{
Child1,
Child2
}
}
</script>
<style scoped>
</style>
Child.vue
<template>
<div class="Child1">
<h1>我是Child1</h1>
<p>name: {{ name }}</p>
<button @click="clickChild1">点击我</button>
</div>
</template>
<script>
export default {
name: 'Child1',
props: ['name'],
methods:{
clickChild1(){
this.$emit('submitToFather','兵哥哥')
}
}
}
</script>
Child2.vue
<template>
<div class="Child2">
<h1>我是Child2组件</h1>
<p>name: {{ name }}</p>
</div>
</template>
<script>
export default {
name: 'Child2',
props: ['name']
}
</script>
App.vue
<template>
<div id="app">
<img src="./assets/logo.png">
<Father />
</div>
</template>
<script>
import Father from './components/Father'
export default {
name: 'App',
components:{
Father
}
}
</script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
index.js
import Vue from 'vue'
import Router from 'vue-router'
import Father from '@/components/Father'
import VueRouter from 'vue-router'
Vue.use(Router)
const routes= [
{
path: '/',
name: 'Father',
component: Father
}
]
const routers = new VueRouter({
mode:'history',
routes
})
export default routers
2.通过在main.js中创建一个Vue的实例Vue2给Child1和Child2访问,其中Child1使用$emit自定义事件传值给Vue2,Child2通过监听Vue2的自定义事件来改变name的值,效果如下:
启动项目后,初始页面显示如下:
点击子组件Child1的“点击我”按钮后,可以看到Child1和Child2的name值都被改变,但没有改变父组件的name值
vue项目文件的核心部分如下:
文件内容如下:
Child1.vue
<template>
<div class="Child1">
<h1>我是组件1</h1>
<p>name: {{ realName }}</p>
<button @click="submitToChild2">点击我</button>
</div>
</template>
<script>
//在main.js中引入Vue2这个实例对象,通过Vue2实例对象的$emit事件来传值给Child2
import { Vue2 } from '../main'
export default {
name: 'Child1',
props: ['name'],
data(){
return{
realName: this.name
}
},
methods:{
submitToChild2(){
this.realName = "兵哥哥"
Vue2.$emit('submitChild2','兵哥哥')
}
}
}
</script>
Child2.vue
<template>
<div class="Child2">
<h1>我是组件2</h1>
<p>name :{{ realName }}</p>
</div>
</template>
<script>
import { Vue2 } from '../main' //引入Vue2实例对象,通过监听Child1的自定义事件,来改变当前的name值
export default {
name: 'Child2',
props: ['name'],
data(){
return{
realName:this.name
}
},
created(){
Vue2.$on('submitChild2',(name) => {
this.realName = name
})
}
}
</script>
Father.vue
<template>
<div class="hello">
<h1>我是父组件</h1>
<p>name :{{ name }}</p>
<Child1 :name="name" />
<Child2 :name="name" />
</div>
</template>
<script>
import Child1 from './Child1'
import Child2 from './Child2'
export default {
name: 'Father',
data () {
return {
name: '椰子'
}
},
components:{
Child1,
Child2
}
}
</script>
main.js
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from './router'
Vue.config.productionTip = false
//在这里新建一个Vue的实例,暴露出去,可以让子组件之间通信
export const Vue2 = new Vue();
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
components: { App },
template: '<App/>'
})
index.js
import Vue from 'vue'
import Router from 'vue-router'
import Father from '@/components/Father'
import VueRouter from 'vue-router'
Vue.use(Router)
const routes = [
{
path: '/',
name: 'Father',
component: Father
}
]
const routers = new VueRouter({
mode: 'history',
routes
})
export default routers
App.vue
<template>
<div id="app">
<img src="./assets/logo.png">
<Father />
</div>
</template>
<script>
import Father from './components/Father'
export default {
name: 'App',
components:{
Father
}
}
</script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
3.通过引入store实例 (const store = new Vuex.Store()),让子组件Child1和Child2通过$store.state.name来获取Vuex中的数据;在Child1组件中通过点击按钮触发commit事件,进而触发Vuex中的mutation函数,改变state.name值改变,带动Child1和Child2组件改变
启动项目后,初始页面显示如下:
点击按钮后
项目结构如下:
核心代码如下:
Child1.vue(请详看注释,可帮助理解)
<template>
<div class="Child1">
<h1>我是子组件1</h1>
//这个地方的 $store.state.name 就是从index.js 中暴露的store实例中获取的
<p>name: {{ $store.state.name }}</p>
<button @click="submitToStore">点击我</button>
</div>
</template>
<script>
export default {
methods:{
submitToStore(){
//通过自定义事件向Vuex中commit一个changeName事件
//这个changeName事件一开始就已经写在store.mutation.changeName中了
this.$store.commit('changeName')
}
}
}
</script>
Child2.vue
<template>
<div class="Child2">
<h1>我是子组件2</h1>
<p>name: {{ $store.state.name }}</p>
</div>
</template>
<script>
export default {
}
</script>
Father.vue
<template>
<div class="Father">
<h1>我是父组件</h1>
<p>name: {{ name }}</p>
<Child1 />
<Child2 />
</div>
</template>
<script>
import Child1 from './Child1'
import Child2 from './Child2'
export default {
name: 'Father',
data () {
return {
name: '椰子'
}
},
components:{
Child1,
Child2
}
}
</script>
main.js
import Vue from 'vue'
import App from './App'
import store from './store'
new Vue({
render: h => h(App),
store,
}).$mount('#app')
store下的index.js
import Vue from "vue"
import Vuex from "vuex"
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
name: '椰子'
},
//mutations是操作state数据的方法的集合,比如对该数据的修改、增加、删除等等。
mutations: {
changeName(state){
state.name = "兵哥哥"
}
}
})
export default store
App.vue
<template>
<div id="app">
<img src="./assets/logo.png">
<Father />
</div>
</template>
<script>
import Father from './components/Father'
export default {
name: 'App',
components:{
Father
}
}
</script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>