vue兄弟组件传值之间的那些爱恨情仇

本文介绍了三种在Vue.js中实现兄弟组件间通信的方法:1) 使用props和$emit;2) 创建中间Vue实例进行事件传递;3) 通过Vuex状态管理。在示例中详细展示了每种方法的实现过程和代码示例,帮助开发者理解不同场景下如何进行组件间通信。
摘要由CSDN通过智能技术生成

      对于学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自定义事件传值给Vue2Child2通过监听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>

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值