【全网最全】Vue 组件之间的传值

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");

未完,更新中…

  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值