本文版权归 “公众号 | 前端一万小时” 所有,欢迎转载!
转载请注明出处,未经同意,不可修改文章内容。
🔥🔥🔥本系列文章已在“公众号 | 前端一万小时”更新完毕,有需要的小伙伴可按需前往查看。
🔥🔥🔥“前端一万小时”两大明星专栏——“从零基础到轻松就业”、“前端面试刷题”,已于本月大改版,合二为一,干货满满,欢迎点击公众号菜单栏各模块了解。
涉及面试题:
组件间的通信?
[编号:vue_18]
Vue 官方对 Vue 框架的定义是一个轻量级的视图层框架,当项目中出现很复杂的数据传递时(主要在于同级组件之间需要进行数据传递的话,如果单纯地靠一层层地传递,可能会让项目变得复杂)。
所以光靠 Vue 框架是解决不了复杂数据的传递,此时我们需要引入一些工具或者设计模式来解决 Vue 之中组件间复杂的数据传递。
1 非父子组件间的数据传递两种方案
- 借助 Vue 官方提供的一个数据层的框架——Vuex ;
- 发布订阅模式(又称为:总线机制/Bus/观察者模式)——本篇文章我们主要学习这种方案!
2 子组件内容是如何根据外部传递的内容进行显示
<body>
<div id="root">
<child content="hello"></child>
<child content="world"></child>
</div>
<script>
Vue.component("child", {
props: {
content: String
},
template: "<div>{{content}}</div>"
})
var vm = new Vue({
el: "#root"
})
</script>
</body>
3 非父子组件间的传值
❓需求: 有两个非父子组件 1 和 2,当点击子组件 1,组件 1 和 组件 2 的内容随即都变成组件 1 里的内容。组件 2 也一样!
💡答:
- 首先,看一下点击组件本身,在组件本身出现的数据变化——分别弹出各自的内容:
<div id="root">
<child content="hello"></child>
<child content="world"></child>
</div>
<script>
Vue.component("child", {
props: {
content: String
},
template: '<div @click="handleClick">{{content}}</div>',
methods: {
handleClick: function() {
alert(this.content)
}
}
})
var vm = new Vue({
el: "#root"
})
</script>
- 再看看如何把数据传递给另一个组件:
<div id="root">
<child content="hello"></child>
<child content="world"></child>
</div>
<script>
Vue.prototype.bus = new Vue () // 注释1️⃣:挂载了一个 bus 的属性;
Vue.component("child", {
data: function() {
// ❗️基于“单向数据流”,我们将接收到的“数据”复制一份放在子组件 data 的 selfContent 里。
return {
selfContent: this.content
}
},
props: {
content: String
},
template: '<div @click="handleClick">{{selfContent}}</div>',
methods: {
handleClick: function() {
this.bus.$emit("change", this.selfContent) /*
注释2️⃣:向外触发事件并携带
要传递的内容数据;
*/
}
}
})
var vm = new Vue({
el: "#root"
})
</script>
- 注释1️⃣:
Vue.prototype.bus = new Vue()
🔗前置知识《JavaScript 基础——面向对象编程:② 使用原型》
在 Vue 的 prototype 上挂载了一个 bus
的属性,该 bus
属性指向一个 Vue 的实例。
在之后,只要调用 new.Vue
或者创建组件时,每个组件上都会有 bus
这个属性(🚀为什么?因为每个 Vue 实例和组件都是通过 Vue 这个类进行创建的,而在 Vue 的 prototype 上挂载一个 bus
的属性,都指向同一个 Vue 的实例)。
- 注释2️⃣:
this.bus.$emit('change', this.content)
this.bus
指的就是 Vue.prototype.bus = new Vue ()
上挂载的 bus ,同时 bus 作为 Vue 实例,有其方法,这里可以用 $
调用这个 emit
,以此向外触发事件并同时携带要传递的内容数据。
- 向外触发事件之后,其他组件将通过“监听”的方式接收数据(❗️借助生命周期钩子):
<body>
<div id="root">
<child content="hello"></child>
<child content="world"></child>
</div>
<script>
Vue.prototype.bus = new Vue () /*
❗️这行代码两个作用:
①:使每个实例都挂载 bus 这个属性;
②:使 bus 就是一个 Vue 的“对象实例”。
*/
Vue.component('child', {
data: function() {
return {
selfContent: this.content
}
},
props: {
content: String
},
template: '<div @click="handleClick">{{selfContent}}</div>',
methods: {
handleClick: function() {
this.bus.$emit('change', this.selfContent)
}
},
mounted: function(){
var this_ = this // ❗️我们需要在这里对 this 作一个保存;
this.bus.$on('change', function(msg) {
/*
❗️让这个组件去监听 bus 的改变。而 bus 本身就是一个实例,
那么它就可以通过 $on 监听 bus 触发出来的事件。
*/
this_.selfContent = msg // ❗️这里就可以用保存了的 this。
})
}
})
var vm = new Vue({
el: "#root"
})
</script>
</body>
祝好,qdywxs ♥ you!