为什么需要使用组件通信?
组件是一个孤岛,所有的组件都无法直接访问其他组件的data,methods,computed,也就说每个组件都是一个局部作用域,这样做的目的是为了保护私有变量,保证每个组件之间的data不会相互影响.
但是在vue中我们经常需要在组件之间进行通信,下面我就来说说组件之间的几种通信方式:
父子组件之间通信原理大致就是如图所示:
1.父传子
父传子我们一般通过动态绑定属性的方式获取,即在子组件标签上绑定属性,然后在子组件中用props来接收.
<body>
<!-- 父组件 -->
<div id="app">
<!-- 子组件 -->
<child mytitle="home" :mytext="text" :myshow='true'></child>
</div>
</body>
</html>
<script>
// 全局组测的子组件
Vue.component("child",{
template:`
<div>
<button v-if="myshow">返回</button>
<span>我是导航栏--{{mytitle}}--{{mytext}}</span>
<button v-show="myshow">主页</button>
</div>
`,
// props:["mytitle","mytext","myshow"],数组方式接收
props:{ //对象方式接收,可以定义接收的数据类型
mytitle:String,
mytext:String,
myshow:Boolean
}
})
var vm=new Vue({
el:"#app",
data:{
text:"我是在父组件中定义的",
}
})
</script>
2.子传父
子传父通过事件绑定的方式进行传递: 在子组件标签上绑定事件,在子组件中用this.$ emit来触发事件执行函数,并且可以传递参数即this.$ emit(“事件”,参数),函数在父组件中执行后就可以得到传递过来的参数.
<body>
<!-- 父组件 -->
<div id="app">
<!-- 子组件 -->
<!-- 在子组件上绑定两个事件event1和event2 -->
<!-- 事件后面的函数如果加括号的话,参数要写成$event才能接收到,
不加括号的话默认能接收到,推荐不加括号 -->
<my-child @event1="handleEvent1($event)" @event2="handleEvent2">
</my-child>
</div>
</body>
</html>
<script>
Vue.component("myChild",{
template:`
<div>
child-<button @click="handleClick()">Click</button>
</div>
`,
data(){
return {
text:"child定义的状态"
}
},
methods:{
handleClick(){
// 子组件中通过this.$emit来触发绑定的事件并进行传参
this.$emit("event1",1000000000)
this.$emit("event2",this.text)
}
}
})
var vm=new Vue({
el:"#app",
methods:{
// 事件被触发执行后,函数会收到子组件传过来的参数
handleEvent1(data){
console.log("收到钱了--1",data) // 收到钱了--1 1000000000
},
handleEvent2(data){
console.log("收到了--2",data) // 收到了--2 child定义的状态
}
}
})
</script>
3.通过给组件绑定ref属性来进行通信
ref绑定在组件上,可以通过this.refs拿到组件对象. ref绑定在dom节点上,通过this.refs拿到的是原生dom节点.
但是这种方式太过暴力,暴露了vue并不是严格的MVVM模式,所有组件都可以随意修改拿到后的数据,所以不推荐使用.
<body>
<div id="app">
<!-- 绑定在标签上 -->
<input type="text" ref="mytext">
<button @click="handleClick()">Click</button>
<!-- 绑定在组件上 -->
<child1 ref="mychild"></child1>
</div>
</body>
</html>
<script>
Vue.component("child1",{
template:`
<div>{{name}}</div>
`,
data(){
return {
name:"Stephen--child1定义的"
}
}
})
var vm=new Vue({
el:"#app",
data:{
},
methods:{
handleClick(){
console.log(this.$refs.mytext.value) //可以拿到输入框的值
console.log(this.$refs.mychild.name) // (Stephen--child1定义的)
this.$refs.mychild.name="Kerwin" //可以随意修改
console.log(this.$refs.mychild.name) //kerwin
}
}
})
</script>
4.中央事件总线
中央事件总线通信原理图:
中央事件总线通过重新new一个vue实例Bus,需要传递数据的组件可以通过bus.$ emit将数据传输给Bus,需要接收数据的组件则通过bus.$ on来接收传给Bus的数据.即this.$ emit(‘事件名’,参数)传送, this.$on(‘事件名’,(data)=>{})接收,bus通信一般用在非父子组件之间进行通信,比如下面例子中的child1hechild2兄弟组件之间.
<script>
var bus = new Vue() //中央事件总线 bus.$on接收,bus.$emit传送
// 组件1
Vue.component("child1", {
template: `
<div>
child1-<button @click="handleClick()">click</button>
</div>
`,
methods: {
handleClick() {
bus.$emit("kerwinevent", "来自child1的问候") //将组件1里面的参数
//通过事件kerwinevent
//以bus.$emit的方式传送给bus中央事件总线
}
},
})
// 组件2
Vue.component("child2", {
template: `
<div>
child2
{{str}}
</div>
`,
data() {
return {
str: ""
}
},
mounted() {
bus.$on("kerwinevent", (data) => { //组件2中通过bus.$on的方式
//从bus中央事件总线上接收对应事件kerwinevent的数据
this.str = data //"来自child1的问候"
})
}
})
var vm = new Vue({
el: "#app",
})
</script>
5.状态管理 Vuex
在大型组件开发项目中,通信会变得越来越频繁,不同组件之间的关系变得越来越复杂,异步请求的数据需要重复使用,这时候我们就需要用到vuex了.
首先vuex是什么?
官方定义:Vuex是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化.
我的理解:也就是说在项目中我们需要共享的状态,不同页面(组件)之间需要共享的ajax请求数据,都可以存到vuex中,然后以一定的规则进行存储和拿取.
vuex的状态管理模式:
- state:单一状态树 ,每个应用将仅仅包含一个 store 实例。
- getters:可以从store 中的state 中派生出一些状态,getters的返回值会根 据 它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。可以认为是store 的计算属性
- mutations:更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。
- actions: Action 提交的是 mutation,而不是直接变更状态。 Action 可
以包含任意异步操作。
什么情况下我应该使用 Vuex?
Vuex 可以帮助我们管理共享状态,并附带了更多的概念和框架。这需要对短期和长期效益进行权衡。如果您不打算开发大型单页应用,使用 Vuex 可能是繁琐冗余的。确实是如此——如果您的应用够简单,您最好不要使用 Vuex。一个简单的 store 模式就足够您所需了。但是,如果您需要构建一个中大型单页应用,您很可能会考虑如何更好地在组件外部管理状态,Vuex 将会成为自然而然的选择。
结尾:以上就是我对vuex中组件间的通信技术的总结,不足的地方望补充(逆战班).