vue组件通信大总结

1. props / $emit

父组件给子组件添加属性:msg="msg"传值,子组件通过props:['msg']接收;
子组件可以通过this.$emit('changeMsg','Welcome')向父组件发送事件和数据,
父组件通过 @changeMsg="change" 监听事件和传递过来的数据。

代码

<!-- Parent.vue -->
<template>
    <div>
        <son :msg="msg" @changeMsg="change" />
    </div>
</template>

<script>
import Son from './Son.vue'
export default {
    name: 'Parent',
    data () {
        return {
            msg: '你好'
        }
    },
    components: {
        Son
    },
    methods: {
        change (msg) {
            this.msg = msg
        }
    }
}
</script>
<!-- Son.vue -->
<template>
    <div>
        {{ msg }}
        <button @click="sendToParent">传递到Parent</button>
    </div>
</template>

<script>
export default {
    name: 'Son',
    props: ['msg'],
    methods: {
        sendToParent () {
            this.$emit('changeMsg', 'Welcome')
        }
    }
}
</script>

效果
在这里插入图片描述

适用于父子组件通信

2. sync / update

v2.3新增语法糖,会扩展成一个更新父组件绑定值的 v-on侦听器;

<son :msg.sync="msg" />
子组件update:msg直接修改数据,父组件无需定义监听事件来接收数据;

适合基本数据类型的传递和修改

<!-- Parent.vue -->
<template>
    <div>
        <son :msg.sync="msg" />
    </div>
</template>

<script>
import Son from './Son.vue'
export default {
    name: 'Parent',
    data () {
        return {
            msg: '你好'
        }
    },
    components: {
        Son
    }
}
</script>
<!-- Son.vue -->
<template>
    <div>
        {{ msg }}
        <button @click="sendToParent">传递到Parent</button>
    </div>
</template>

<script>
export default {
    name: 'Son',
    props: ['msg'],
    methods: {
        sendToParent () {
            this.$emit('update:msg', 'Welcome')
        }
    }
}
</script>

3. provide / inject

父组件通过provide传值,子组件通过inject:["msg"]接收,provide传递的数据, 不仅所有子组件都可以接收,所有后代组件均可以通过inject接收到。

<!-- Parent.vue -->
<template>
    <div>
        <son />
    </div>
</template>

<script>
import Son from './Son.vue'
export default {
    name: 'Parent',
    provide () {
        return {
            pdata: this
        }
    },
    data () {
        return {
            msg: '你好'
        }
    },
    components: {
        Son
    }
}
</script>
<!-- Son.vue -->
<template>
    <div>
        {{ text }}
        <button @click="sendToParent">修改</button>
    </div>
</template>

<script>
export default {
    name: 'Son',
    inject: ['pdata'],
    computed: {
        text () {
            return this.pdata.msg
        }
    },
    methods: {
        sendToParent () {
            this.pdata.msg = 'hello'
        }
    }
}
</script>

4. $attrs / $listeners

v2.4新增

$attrs包含了父作用域中不作为prop 被识别 (且获取) 的属性绑定 (classstyle 除外)。
$listeners 包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器,它可以通过 v-on="$listeners" 传入内部组件。

<!-- Home.vue -->
<template>
  <div class="home">
    <father :name="name" :age="age" @changeName="changeName" @changeAge="changeAge" />
  </div>
</template>

<script>
import Father from './Father.vue'

export default {
    name: 'Home',
    components: {
        Father
    },
    data () {
        return {
            name: '张三',
            age: 30
        }
    },
    methods: {
        changeName (name) {
            this.name = name
        },
        changeAge (age) {
            this.age = age
        }
    }
}
</script>
<!-- Father.vue -->
<template>
    <div>
        {{ age }}
        Father Comp: {{ $attrs }}
        <button @click="updateName">修改Name</button>
        <son v-bind="$attrs" v-on="$listeners" />
    </div>
</template>

<script>
import Son from './Son'
export default {
    name: 'Father',
    props: ['age'],
    components: {
        Son
    },
    methods: {
        updateName () {
            this.$emit('changeName', '李四')
        }
    }
}
</script>
<!-- Son.vue -->
<template>
    <div>
        Son Comp:{{ $attrs }}
        <button @click="updateAge">修改Age</button>
    </div>
</template>

<script>
export default {
    name: 'Son',
    methods: {
        updateAge () {
            this.$emit('changeAge', 40)
        }
    }
}
</script>

效果
在这里插入图片描述

5. $children / $parent

父组件通过$children访问子组件属性和方法,子组件通过$parent访问父组件属性和方法, this.$children[0].age=2修改子组件数据,同理this.$parent.age=30 修改父组件数据。

<!-- Father.vue -->
<template>
    <div>
        Father Age: {{ age }}
        <button @click="updateSonAge">修改Son的Age</button>
        <son />
    </div>
</template>

<script>
import Son from './Son'
export default {
    name: 'Father',
    components: {
        Son
    },
    data () {
        return {
            age: 30
        }
    },
    methods: {
        updateSonAge () {
            this.$children[0].age = 15
        }
    }
}
</script>
<!-- Son.vue -->
<template>
    <div>
        Son Age: {{ age }}
        <button @click="updateFatherAge">修改Father的Age</button>
    </div>
</template>

<script>
export default {
    name: 'Son',
    data () {
        return {
            age: 10
        }
    },
    methods: {
        updateFatherAge () {
            this.$parent.age = 35
        }
    }
}
</script>

效果
在这里插入图片描述

6. ref / refs

子组件绑定ref属性,父组件通过this.$refs['xxx']访问子组件,用法和 $children 相同。
this.$refs['son']===this.$children[0] //true

<!-- Father.vue -->
<template>
    <div>
        Father Age: {{ age }}
        <button @click="updateSonAge">修改Son的Age</button>
        <son ref='son' />
    </div>
</template>

<script>
import Son from './Son'
export default {
    name: 'Father',
    components: {
        Son
    },
    data () {
        return {
            age: 30
        }
    },
    methods: {
        updateSonAge () {
            this.$refs.son.age = 20
        }
    }
}
</script>
<!-- Son.vue -->
<template>
    <div>
        Son Age: {{ age }}
    </div>
</template>

<script>
export default {
    name: 'Son',
    data () {
        return {
            age: 10
        }
    }
}
</script>

7. Vuex

vuex可以说是万金油,因为它是vue的一个状态管理库,任何数据都可以存在这个库里,缺点就是使用方法略微麻烦一点,优点就是不用管什么层级之间的传递数据都是可以的,而且是共享数据,所以还是要看有没有必要使用这个方式,如果数据会在不同的层级,很多地方都需要使用或修改,且数据都是共享的,那么这种方式就是最好的。

<template>
  <div id="app">
    <ChildA/>
    <ChildB/>
  </div>
</template>

<script>
  import ChildA from './components/ChildA'
  import ChildB from './components/ChildB'
  export default {
    name: 'App',
    components: {ChildA, ChildB}
  }
</script>
<template>
  <div id="childA">
    <h1>我是A组件</h1>
    <button @click="transform">点我让B组件接收到数据</button>
    <p>{{BMessage}}</p>
  </div>
</template>

<script>
  export default {
    data() {
      return {
        AMessage: 'Hello,B组件,我是A组件'
      }
    },
    computed: {
      BMessage() {
        return this.$store.state.BMsg
      }
    },
    methods: {
      transform() {
        this.$store.commit('receiveAMsg', {
          AMsg: this.AMessage
        })
      }
    }
  }
</script>
<template>
  <div id="childB">
    <h1>我是B组件</h1>
    <button @click="transform">点我让A组件接收到数据</button>
    <p>{{AMessage}}</p>
  </div>
</template>

<script>
  export default {
    data() {
      return {
        BMessage: 'Hello,A组件,我是B组件'
      }
    },
    computed: {
      AMessage() {
        return this.$store.state.AMsg
      }
    },
    methods: {
      transform() {
        this.$store.commit('receiveBMsg', {
          BMsg: this.BMessage
        })
      }
    }
  }
</script>
/**
 * store.js 
 */
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

const state = {
  AMsg: '',
  BMsg: ''
}
const mutations = {
  receiveAMsg(state, payload) {
    state.AMsg = payload.AMsg
  },
  receiveBMsg(state, payload) {
    state.BMsg = payload.BMsg
  }
}

export default new Vuex.Store({
  state,
  mutations
})

8. EventBus

eventBus又称为事件总线,在vue中可以使用它来作为沟通桥梁的概念, 就像是所有组件共用相同的事件中心,可以向该中心注册发送事件或接收事件, 所有组件都可以通知其他组件。(维护困难,eventName起名字困难,不易维护,不及时注销事件会产生各种问题,复杂项目中还是使用Vuex

//新建一个Vue实例作为中央事件总线
let EventBus = new Vue();
//监听事件
EventBus.$on('eventName', (val) => {
	//......do something
});
//触发事件
EventBus.$emit('eventName', 'this is a message.');
//移除事件
EventBus.$off('eventName', {})

9. localStorage/sessionStorage

本地存储,某些业务中使用较多,比如记住用户token用户信息系统设置
window.localStorage.getItem(key)获取数据,通过 window.localStorage.setItem(key,value) 存储数据;

注意:value只能是字符串类型,需要用JSON.parse() / JSON.stringify()转换
sessionStorage同理。

总结

特点
props / $emit最常用的父子组件通信
sync/update父子组件基本数据类型,适用于子组件修改父组件数据
provide/inject多层级传递,不受子孙组件的影响,适用于插槽,嵌套插槽;不适合兄弟通讯,父级组件无法主动通信
$attrs / $listeners主要时解决了props传递数据不能跨层的缺点,但无法兄弟传参
$children / $parent方便直接,但 this.$children不可控性大,有一定风险。(尽量不用)
ref / refs渲染完成后才可使用,不是响应式的,时不时配合$nextTick
vuex处理复杂的组件通信的最佳方案,支持异步组件通信,缺点是流程相比稍微复杂
EventBus简单灵活,父子兄弟通信不受限制,通信方式不受框架影响,但维护困难,需要谨小慎微的命令规范,不利于组件化开发
localStorage / sessionStorage常用于存储用户信息,系统设置,token等
  • 父子组件通信: props / $emit; .sync/updateprovide/inject; $parent / $children; ref/refs; $attrs/$listeners

  • 非父子组件/兄弟组件通信: EventBus ; VuexlocalStorage/sessionStorage

  • 7
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

优小U

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值