1.组件间的传值方法简述
- 父组件 =data=> 子组件
- 子组件通过 props
- 子组件 =data=> 父组件
- 父组件向子组件传递一个函数(callback)
- 使用 $emit 自定义事件
- 使用 .sync 简化并实现传值的双向绑定
- 爷组件 =data=> 孙组件
- 在孙组件上使用 v-bind="$attrs"
- 孙组件 =data=>爷组件
- 在孙组件上使用 v-on="$listeners"
- 兄弟组件【方法且适用于以上所有】
- 采用全局事件总线 $bus
- 采用第三方库 pubsub【订阅发布】
- 采用 Vuex 状态管理库
【在开始之前使用到的三个组件在这里做一个简单的展示】
1.爷组件
<template>
<div class="Granpa">
<h3>我是GrandPa组件</h3>
<div class="inner">
<h5>下面是Father组件</h5>
<Father></Father>
</div>
</div>
</template>
<script>
import Father from "./Father.vue";
import "../../assets/comment.css";
export default {
data() {
return {};
},
components: {
Father,
},
};
</script>
<style lang="scss" scoped>
.Granpa {
width: 260px;
height: max-content;
padding: 40px;
background: red;
}
.inner {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
</style>
2.父组件
<template>
<div class="Father">
<h3>我是Father组件</h3>
<div class="center">
<h5>下面是Son组件</h5>
<Son></Son>
</div>
</div>
</template>
<script>
import Son from "./Son.vue";
import "../../assets/comment.css";
export default {
// 引入Son组件
components: {
Son,
},
data() {
return {};
},
};
</script>
<style lang="scss" scoped>
.Father {
width: 150px;
height: max-content;
background: green;
padding: 40px;
// margin: auto;
}
.center {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
</style>
3.孙组件
<template>
<div class="Son">
<h3>我是Son组件</h3>
<div></div>
</div>
</template>
<script>
import "../../assets/comment.css";
export default {
data() {
return {};
},
};
</script>
<style lang="scss" scoped>
.Son {
width: 100px;
height: max-content;
background: yellow;
padding: 40px;
}
</style>
4.公共样式库 comment.css
h3 {
color: white;
font-size: 16px;
}
运行效果如下:
1.父组件 =data=> 子组件
父组件向子组件传值主要使用到了 v-bind 【简写“:”】指令和 props 选项(option),比如现在我们将 msg:"儿砸" 传递给子组件,并在子组件中进行一个展示。
1.父组件
<template>
<div class="Father">
<h3>我是Father组件</h3>
<div class="center">
<h5>下面是Son组件</h5>
<Son :toSonMsg="msg"></Son>
</div>
</div>
</template>
<script>
import Son from "./Son.vue";
import "../../assets/comment.css";
export default {
// 引入Son组件
components: {
Son,
},
data() {
return {
msg: "儿砸",
};
},
};
</script>
<style lang="scss" scoped>
.Father {
width: 150px;
height: max-content;
background: green;
padding: 40px;
// margin: auto;
}
.center {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
</style>
2.子组件
<template>
<div class="Son">
<h3>我是Son组件</h3>
<div>
这是父组件传递给我的消息<i>{{ toSonMsg }}</i>
</div>
</div>
</template>
<script>
import "../../assets/comment.css";
export default {
props: {
toSonMsg: String,
},
data() {
return {};
},
};
</script>
<style lang="scss" scoped>
.Son {
width: 100px;
height: max-content;
background: yellow;
padding: 40px;
}
</style>
效果:
2.子组件 =data=> 父组件
Ⅰ。利用【父组件向子组件传值,向子组件传递一个函数】假设我们传递的消息是 msg:"爸比",其中 sendFunction 就是父组件传递给子组件的 函数 (其中参数就是子组件传给父组件的值),toSonFunc 是子组件所期望得到的值【数据类型应为 Function】;在子组件定义单击事件 sendMsgFather 然后调用 函数toSonFunc 来实现 子组件向父组件传值。
1.父组件
<template>
<div class="Father">
<h3>我是Father组件</h3>
<div>
这是Son组件传递给我的值<i>{{ showMsg }}</i>
</div>
<div class="center">
<h5>下面是Son组件</h5>
<Son :toSonFunc="sendFunction"></Son>
</div>
</div>
</template>
<script>
import Son from "./Son.vue";
import "../../assets/comment.css";
export default {
// 引入Son组件
components: {
Son,
},
data() {
return {
showMsg: "",
};
},
methods: {
// 函数
sendFunction: function (valueFromSon) {
this.showMsg = valueFromSon;
},
},
};
</script>
<style lang="scss" scoped>
.Father {
width: 150px;
height: max-content;
background: green;
padding: 40px;
// margin: auto;
}
.center {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
</style>
2.子组件
<template>
<div class="Son">
<h3>我是Son组件</h3>
<div>
<button @click="sendMsgFather">发送消息给Father</button>
</div>
</div>
</template>
<script>
import "../../assets/comment.css";
export default {
props: {
toSonFunc: Function,
},
data() {
return {
msg: "爸比",
};
},
methods: {
sendMsgFather: function () {
this.toSonFunc(this.msg);
},
},
};
</script>
<style lang="scss" scoped>
.Son {
width: 100px;
height: max-content;
background: yellow;
padding: 40px;
}
</style>
效果:
Ⅱ。【使用 $emit 自定义事件 实现】并设置传值为 msg: "爸比,你会唱小星星么?",当 $emit “发射,触发”后 会执行 @toFatherClick 该自定义事件 中的回调 函数 sendFunction; 【回调函数的触发时机正是当 函数 “发射,触发” 后回调会被执行】
1.父组件
<template>
<div class="Father">
<h3>我是Father组件</h3>
<div>
这是Son组件传递给我的值<i>{{ showMsg }}</i>
</div>
<div class="center">
<h5>下面是Son组件</h5>
<Son @toFatherClick="sendFunction"></Son>
</div>
</div>
</template>
<script>
import Son from "./Son.vue";
import "../../assets/comment.css";
export default {
// 引入Son组件
components: {
Son,
},
data() {
return {
showMsg: "",
};
},
methods: {
// 函数
sendFunction: function (valueFromSon) {
this.showMsg = valueFromSon;
},
},
};
</script>
<style lang="scss" scoped>
.Father {
width: 150px;
height: max-content;
background: green;
padding: 40px;
// margin: auto;
}
.center {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
</style>
2.子组件
<template>
<div class="Son">
<h3>我是Son组件</h3>
<div>
<button @click="sendMsgFather">发送消息给Father</button>
</div>
</div>
</template>
<script>
import "../../assets/comment.css";
export default {
data() {
return {
msg: "爸比,你会唱小星星么?",
};
},
methods: {
sendMsgFather: function () {
this.$emit("toFatherClick", this.msg);
},
},
};
</script>
<style lang="scss" scoped>
.Son {
width: 100px;
height: max-content;
background: yellow;
padding: 40px;
}
</style>
效果
Ⅲ。.sync 可以简化这个传值的一个过程,并实现父组件传递给子组件的值的一个双向绑定
【举个简单的栗子 就是子组件中的按钮 控制 父组件中的显示与隐藏】
如果刚开始直接写 .sync 可能有点突兀【这一点官网上写得并不是太好】,而且不太好理解,我们以最常规的 子组件 向 父组件 传值为基础 来走一遍思路。
1.父组件
<template>
<div class="Father">
<h3>我是Father组件</h3>
<div class="box" v-show="isShow">
<h1>我是可以隐藏的标题</h1>
</div>
<div class="center">
<h5>下面是Son组件</h5>
<Son :isShow="isShow" @toFatherClick="changeShow"></Son>
</div>
</div>
</template>
<script>
import Son from "./Son.vue";
import "../../assets/comment.css";
export default {
// 引入Son组件
components: {
Son,
},
data() {
return {
// 控制着 盒子的显示(true) 和 隐藏(false)
isShow: true,
};
},
methods: {
changeShow: function (val) {
this.isShow = val;
},
},
};
</script>
<style lang="scss" scoped>
.Father {
width: 150px;
height: max-content;
background: green;
padding: 40px;
}
.center {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.box {
width: 120px;
height: 120px;
background: pink;
margin: auto;
}
</style>
2.子组件
<template>
<div class="Son">
<h3>我是Son组件</h3>
<div>
<button @click="sendMsgFather">点击我隐藏/显示Father中的title</button>
</div>
</div>
</template>
<script>
import "../../assets/comment.css";
export default {
props: ["isShow"],
data() {
return {};
},
methods: {
sendMsgFather: function () {
this.$emit("toFatherClick", !this.isShow);
},
},
};
</script>
<style lang="scss" scoped>
.Son {
width: 100px;
height: max-content;
background: yellow;
padding: 40px;
}
</style>
效果
接下来我们就要对相关的代码进行一个变形了,首先是父组件中的一下几处
......
<Son :isShow="isShow" @toFatherClick="changeShow"></Son>
......
methods: {
changeShow: function (val) {
this.isShow = val;
},
},
......
改变以后的,上面的代码可以精简为以下【说明:changeShow 中的默认传递的参数是 $event ,这里是比较特殊的 这个$event 其实就是 子元素那边传递过来的值(载荷)】
<Son :isShow="isShow" @toFatherClick="isShow = $event"></Son>
然后就是 子组件 里面的自定义事件的名称 原来是 toFatherClick 现在我们更改为 update:isShow 【注意你没有看错,这个事件的中间有 ":" 并不是有什么实际意义】
//原来的
sendMsgFather: function () {
this.$emit("toFatherClick", !this.isShow);
},
//改变之后的
sendMsgFather: function () {
this.$emit("update:isShow", !this.isShow);
},
【相信 有了上面的这个解释 就连官网的 介绍 应该都能看懂了呢 这里】
更改过自定义事件后,那么 在父组件中的 Son 就变成了这样【太长、太复杂】
<Son :isShow="isShow" @update:isShow="isShow = $event"></Son>
使用 sync 后,就变得非常的简洁了。
<Son :isShow.sync="isShow"></Son>
改变以后的代码附上,感兴趣的小伙伴可以试试
父组件更改变以后的代码
<template>
<div class="Father">
<h3>我是Father组件</h3>
<div class="box" v-show="isShow">
<h1>我是可以隐藏的标题</h1>
</div>
<div class="center">
<h5>下面是Son组件</h5>
<Son :isShow.sync="isShow"></Son>
</div>
</div>
</template>
<script>
import Son from "./Son.vue";
import "../../assets/comment.css";
export default {
// 引入Son组件
components: {
Son,
},
data() {
return {
// 控制着 盒子的显示(true) 和 隐藏(false)
isShow: true,
};
},
};
</script>
<style lang="scss" scoped>
.Father {
width: 150px;
height: max-content;
background: green;
padding: 40px;
}
.center {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.box {
width: 120px;
height: 120px;
background: pink;
margin: auto;
}
</style>
子组件改变以后的代码
<template>
<div class="Son">
<h3>我是Son组件</h3>
<div>
<button @click="sendMsgFather">点击我隐藏/显示Father中的title</button>
</div>
</div>
</template>
<script>
import "../../assets/comment.css";
export default {
props: ["isShow"],
data() {
return {};
},
methods: {
sendMsgFather: function () {
this.$emit("update:isShow", !this.isShow);
},
},
};
</script>
<style lang="scss" scoped>
.Son {
width: 100px;
height: max-content;
background: yellow;
padding: 40px;
}
</style>
3.爷组件=data=> 孙组件
假设我们现在需要 爷组件向 孙组件传递一个消息 sendMessage: "真是爷爷的乖孙子!!!"
其实是有两种思路的,最容易想到的就是 爷组件传父组件 父组件传子组件【但是采用这种普通的方式代码不够精简】,另一种就是使用 v-bind="$attrs" 会直接跨过 有该属性的 组件,到下一级组件【像一根导管一样】,正常使用props 进行接收即可。
1.爷组件
<template>
<div class="Granpa">
<h3>我是GrandPa组件</h3>
<div class="inner">
<h5>下面是Father组件</h5>
<Father :sendMessage="sendMessage"></Father>
</div>
</div>
</template>
<script>
import Father from "./Father.vue";
import "../../assets/comment.css";
export default {
data() {
return {
sendMessage: "真是爷爷的乖孙子!!!",
};
},
components: {
Father,
},
};
</script>
<style lang="scss" scoped>
.Granpa {
width: 260px;
height: max-content;
padding: 40px;
background: red;
}
.inner {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
</style>
2.父组件
<template>
<div class="Father">
<h3>我是Father组件</h3>
<div class="center">
<h5>下面是Son组件</h5>
<Son v-bind="$attrs"></Son>
</div>
</div>
</template>
<script>
import Son from "./Son.vue";
import "../../assets/comment.css";
export default {
// 引入Son组件
components: {
Son,
},
data() {
return {};
},
};
</script>
<style lang="scss" scoped>
.Father {
width: 150px;
height: max-content;
background: green;
padding: 40px;
}
.center {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.box {
width: 120px;
height: 120px;
background: pink;
margin: auto;
}
</style>
3.孙组件
<template>
<div class="Son">
<h3>我是Son组件</h3>
<div>这是爷爷想要给我说的:{{ sendMessage }}</div>
</div>
</template>
<script>
import "../../assets/comment.css";
export default {
props: {
sendMessage: String,
},
data() {
return {};
},
methods: {},
};
</script>
<style lang="scss" scoped>
.Son {
width: 100px;
height: max-content;
background: yellow;
padding: 40px;
}
</style>
效果
4.孙组件=data=> 爷组件
思路与 爷组件 向 孙组件传值 类似,只不过我们在这里要使用 一个 v-on="$listeners",假如我们向 爷组件传递一个 msgToGranPa : "爷爷我想你了"
1.爷组件
<template>
<div class="Granpa">
<h3>我是GrandPa组件</h3>
<div>这是孙子传过来的消息:{{ msg }}</div>
<div class="inner">
<h5>下面是Father组件</h5>
<Father @sendMsgPa="getMsg"></Father>
</div>
</div>
</template>
<script>
import Father from "./Father.vue";
import "../../assets/comment.css";
export default {
data() {
return {
// 孙子传递过来的消息
msg: "",
};
},
components: {
Father,
},
methods: {
getMsg: function (val) {
this.msg = val;
},
},
};
</script>
<style lang="scss" scoped>
.Granpa {
width: 260px;
height: max-content;
padding: 40px;
background: red;
}
.inner {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
</style>
2.父组件
<template>
<div class="Father">
<h3>我是Father组件</h3>
<div class="center">
<h5>下面是Son组件</h5>
<Son v-on="$listeners"></Son>
</div>
</div>
</template>
<script>
import Son from "./Son.vue";
import "../../assets/comment.css";
export default {
// 引入Son组件
components: {
Son,
},
data() {
return {};
},
};
</script>
<style lang="scss" scoped>
.Father {
width: 150px;
height: max-content;
background: green;
padding: 40px;
}
.center {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.box {
width: 120px;
height: 120px;
background: pink;
margin: auto;
}
</style>
3.孙组件
<template>
<div class="Son">
<h3>我是Son组件</h3>
<div>
<button @click="sendMsgToGrandPa">点击我给爷爷留言</button>
</div>
</div>
</template>
<script>
import "../../assets/comment.css";
export default {
data() {
return {
msgToGranPa: "爷爷我想你了",
};
},
methods: {
sendMsgToGrandPa: function () {
this.$emit("sendMsgPa", this.msgToGranPa);
},
},
};
</script>
<style lang="scss" scoped>
.Son {
width: 100px;
height: max-content;
background: yellow;
padding: 40px;
}
</style>
效果
5.兄弟组件传值
Ⅰ。采用全局事件总线 $bus(这个是咱们自己定义,可以改,不过为了和人家 Vue 对象上的 方法保持一致 像【$emit $on】等等,所以命名为 $bus)。之前一定有小伙伴听说过 ,但是一定有小伙伴还是不能够理解的吧?其实全局事件总线简单来说就是利用了这样的一个关系 。
VueComponent.prototype.__proto__ === Vue.prototype
起初我们需要在入口文件 main.js 中 注册全局事件总线
new Vue({
router,
render: (h) => h(App),
beforeCreate() {
// vue 原型对象上挂载一个$bus = this 指向当前 vue 实例对象
Vue.prototype.$bus = this;
},
}).$mount("#app");
未完,更新中…