vue2.x的10种组件间通信方式

好记性不如烂笔头,记性不好,总是记混或忘记,整个笔记(非原创),方便使用时候直接查找,省时省力

一、vue 2.X 组件间通信方式表

序号 方式 使用场景 说明
1 props 父=>子(属性传参) 接收数据: 子组件中props定义接收; 派发数据: 父组件中绑定数据进行派发
2 emit/emit/emit/on 子=>父组件通信(事件传参) 接收数据: 父组件调用$on/v-on; 派发数据: 子组件调用$emit()
3 event bus 兄弟组件通信 跨层级组件通信 自定义观察者模式的Bus并挂载到根Vue; 接收数据: 对应组件调用$on; 派发数据: 对应组件调用$emit()
4 $refs 父取子组件通信 通过 <math xmlns="http://www.w3.org/1998/Math/MathML"> r e f s 获取子节点引用直接操作,在父组件中用 t h i s . refs获取子节点引用直接操作,在父组件中用this. </math>refs获取子节点引用直接操作,在父组件中用this.refs.Hello.name
5 $root 兄弟组件通信 接收数据: 对应组件调用根组件的$on() 派发数据: 对应组件调用根组件的$emit()
6 $parent 子取父 接收数据: 对应组件调用公共父组件的$on() 派发数据: 对应组件调用公共父组件的$emit() this.$parent.属性/data/method
7 $children 父子组件通信 通过$children获取并查找指定子节点后直接操作
9 provide/inject 跨多层级组件通信 接收数据: "孙"辈组件通过定义inject获取数据 派发数据: 父组件中通过定义provide设置数据
9 $attrs 父=>孙 (非属性特性传参) 场景1 父孙传参 接收数据: 孙辈组件中props定义接收 桥接数据: 子组件中通过v-bind="$attrs"展开 派发数据: 父组件中绑定数据进行派发 场景2 父子传参 接收数据: 子组件中$attrs.xxx获取数据 派发数据: 父组件中绑定数据进行派发
10 $listeners 孙=>父 (事件传参) 场景1 孙父传参 接收数据: 父组件调用$on/v-on 桥接数据: 子组件中通过v-bind="$listeners"展开 派发数据: 子组件调用$listeners.xxx() 场景2 子父传参 接收数据: 父组件调用$on/v-on 派发数据: 子组件调用$listeners.xxx()
11 slot-scope & v-slot 插槽 cn.vuejs.org/guide/compo...](myimg-1302777074.cos.ap-beijing.myqcloud.com/image-20230...!%255Bimage-20230224170837152 "https://myimg-1302777074.cos.ap-beijing.myqcloud.com/image-20230224112000475.png)!%5Bimage-20230224170837152")](myimg-1302777074.cos.ap-beijing.myqcloud.com/image-20230...)
11 vuex 任意组件通信 通过单独文章说明vuex的使用

二、组件间通信演示

1. props

父=>子

父组件定义数据代码:

javascript 复制代码
<Child :msg="data"/>

data() {
  return {
    data: 'Welcome to Your Vue.js App'
  }
}

子组件定义props接收数据代码

javascript 复制代码
<h1>{{ msg }}</h1>

props: {
  msg: {
    type: String,
      default: ''
  },
}

2. emit&$on

子=>父

子组件派发事件代码

javascript 复制代码
<button @click="sendDataToParent">发送</button>

methods: {
  sendDataToParent() {
    this.$emit("send", "我是子组件");
  },
}

父组件绑定事件代码v1

javascript 复制代码
<Child @send="childSend($event)" />

methods: {
  childSend(value) {
    console.log('value :>> ', value);
  }
}

父组件绑定事件代码v2

javascript 复制代码
<Child ref="child1" />

mounted() {
	this.$refs.child1.$on("send", (value) => {
  	console.log("parent received value is :>> ", value);
	});
}

3. eventbus

兄弟组件之间通讯

自定义bus代码:

javascript 复制代码
/* eslint-disable no-unused-vars */
class Bus {
    constructor() {
        this.callbacks = {}
    }

    on(name, fn) {
        this.callbacks[name] = this.callbacks[name] || []
        this.callbacks[name].push(fn)
    }

    emit(name,args){
        if(this.callbacks[name]){
            this.callbacks[name].forEach(callback => {
                callback(args)
            });
        }
    }
}
module.exports = Bus

子组件1发送数据代码:

javascript 复制代码
<button @click="send">发送</button>

<script>
export default {
  name: "Child",
  methods: {
    send() {
      this.$bus.emit("send", "我是子组件1");
    },
  },
};
</script>

子组件2接收数据代码:

javascript 复制代码
export default {
  name: "Child2",
  mounted() {
    this.$bus.on("send", (value) => {
      console.log("value :>> ", value);
    });
  },
};

公共父组件代码:

javascript 复制代码
<template>
  <div>
    <Child />
    <Child2 />
  </div>
</template>

4. $refs

父取子/父改子/父调子

父组件调用子组件函数/设置数据/获取数据代码:

javascript 复制代码
<Child ref="child1" />

mounted() {
  // ** 注意组件挂载顺序
  // 获取子组件data数据
  console.log("this.$refs.child1.msg :>> ", this.$refs.child1.msg);
  // 修改子组件data数据
  this.$refs.child1.msg = "parent modify data";
  // 调用子组件函数
  this.$refs.child1.childConsole("hello");
}

子组件代码:

javascript 复制代码
<template>
  <div ref="c1" class="hello">
    {{ msg }}
  </div>
</template>

<script>
export default {
  name: "Child",
  data() {
    return {
      msg: "I'm child.",
    };
  },
  mounted() {
    console.log("child msg :>> ", this.msg);
  },
  methods: {
    childConsole(value) {
      console.log("parent value is :>> ", value);
    },
  },
};
</script>

5. $parent

子取父属性/方法

子组件1通过$parent发送数据代码:

javascript 复制代码
<button @click="sendDataToChild2">发送</button>

methods: {
  sendDataToChild2() {
    this.$parent.$emit("send", "我是子组件1");
  },
}

子组件2通过$parent接收数据代码:

javascript 复制代码
mounted () {
  this.$parent.$on('send',(value)=>{
    console.log('child2 received value is :>> ', value);
  })
}

公共父组件代码:

javascript 复制代码
<template>
  <div ref="app">
    <Child />
    <Child2 />
  </div>
</template>

6. $children

父取/调子

父组件调用子组件函数/设置数据/获取数据代码:

javascript 复制代码
<Child ref="child1" />

mounted () {
  console.log('this.$children :>> ', this.$children);
  const children = this.$children[0]
  if(children.$vnode.data.ref === "child1"){
    console.log('children.msg :>> ', children.msg);
    children.message('hello')
  }
}

子组件代码:

javascript 复制代码
<template>
  <div ref="c1" class="hello">
  </div>
</template>

<script>
export default {
  name: "Child",
  data() {
    return {
      msg: "hello vue",
    };
  },
  methods: {
    message(value) {
      console.log("value :>> ", value);
    },
  },
};
</script>

7. root(兄弟)

兄弟

javascript 复制代码
// 发送修改为
this.$root.$emit("send", "我是子组件1");

// 接收修改为
this.$root.$on('send',(value)=>{
  console.log('child2 received value is :>> ', value);
})

8. provide&inject

父=>子&&孙子...

父组件设置provide代码

javascript 复制代码
<Child />

export default {
  provide() {
    return { msg: "hello vue" };
  },
  components: {
    Child,
  },
};

子组件配置孙辈组件代码

javascript 复制代码
<Grandson></Grandson>

export default {
  components: {
    Grandson,
  },
};

孙辈组件通过inject获取数据代码

javascript 复制代码
export default {
    inject: ['msg'],
};

9. $attrs属性传参

案例1(父=>子传参):

1. 父组件传递数据代码:

javascript 复制代码
<Child value="Hello Vue" />

2. 子组件接收数据代码:

javascript 复制代码
<!--非属性特性-为在props中定义-->
<div>{{$attrs.value}}</div>

案例2(父=>孙传参,子桥接):

1. 父组件传递数据代码:

javascript 复制代码
<Child value="Hello Vue" />

2. 子组件桥接属性代码v-bind="$attrs":

javascript 复制代码
<!--非属性特性-为在props中定义-->
<!--利用$attrs展开语法跨层级多参数传递-->
<Grandson v-bind="$attrs"></Grandson>

3. 孙辈组件通过props属性接收数据代码:

javascript 复制代码
<div>{{ value }}</div>

props: {
  value: {
    type: String,
    default: "",
  },
},

10. $listeners事件传参

案例1(子=>父传参)

1. 子组件派发事件代码:

javascript 复制代码
<button @click="send">发送</button>

send() {
  this.$listeners.event('hello vue')
}

3. 父组件绑定事件接收数据代码:

javascript 复制代码
<Child @event="message" />
  
message(value) {
  console.log('value :>> ', value);
}

案例2(孙=>父传参,子桥接)

1. 孙辈组件派发事件代码:

javascript 复制代码
<button @click="send">发送</button>

this.$emit("event", "hello vue");

2. 子组件桥接事件代码v-on="$listeners":

javascript 复制代码
<!--利用$listeners展开语法跨层级多参数传递-->
<Grandson v-on="$listeners"></Grandson>

3. 父组件绑定事件接收数据代码:

javascript 复制代码
<Child @event="message" />
  
message(value) {
  console.log('value :>> ', value);
}

11. slot、slot-scope和v-slot

slot:默认插槽、具名插槽和作用域插槽

1.子组件中:

  • 插槽用<slot>标签来确定渲染的位置,里面放如果父组件没传内容时的后备内容
  • 具名插槽name属性来表示插槽的名字,不传为默认插槽
  • 作用域插槽在作用域上绑定属性来将子组件的信息传给父组件使用,这些属性会被挂在父组件slot-scope接受的对象上。
javascript 复制代码
// Child.vue
<template>
  <div>
    <main>
    <!-- 默认插槽 -->
        <slot>
          <!-- slot内为后备内容 -->
          <h3>没传内容</h3>
        </slot>
    </main>

    <!-- 具名插槽 -->
    <header>
        <slot name="header">
          <h3>没传header插槽</h3>
        </slot>
    </header>

    <!-- 作用域插槽 -->
    <footer>
        <slot name="footer" testProps="子组件的值">
          <h3>没传footer插槽</h3>
        </slot>
    <footer>
  </div>
</template>

<style scoped>
div{
 border: 1px solid #000;  
}
</style>

2.父组件中在使用时:

  • 默认插槽的话直接在子组件的标签内写入内容即可
  • 具名插槽 是在默认插槽的基础上加上slot属性,值为子组件插槽name属性值
  • 作用域插槽 则是通过slot-scope获取子组件的信息,在内容中使用。这里可以用解构语法去直接获取想要的属性
xml 复制代码
// Parent.vue
<child>
  <!-- 默认插槽 -->
  <div>默认插槽</div>  
  <!-- 具名插槽 -->
  <div slot="header">具名插槽header</div>
  <!-- 作用域插槽 -->
  <div slot="footer" slot-scope="slotProps">
    {{slotProps.testProps}}
  </div>
</child>

v-slot

在vue2.6中,上述的API被软废弃(3.0正式废弃),取而代之的是内置指令v-slot,可以缩写为【#】

1.子组件中:

  • 插槽用<slot>标签来确定渲染的位置,里面放如果父组件没传内容时的后备内容
  • 具名插槽name属性来表示插槽的名字,不传为默认插槽
  • 作用域插槽在作用域上绑定属性来将子组件的信息传给父组件使用,这些属性会被挂在父组件slot-scope接受的对象上。
javascript 复制代码
// Child.vue
<template>
  <div>
    <main>
    <!-- 默认插槽 -->
        <slot>
          <!-- slot内为后备内容 -->
          <h3>没传内容</h3>
        </slot>
    </main>

    <!-- 具名插槽 -->
    <header>
        <slot name="header">
          <h3>没传header插槽</h3>
        </slot>
    </header>

    <!-- 作用域插槽 -->
    <footer>
        <slot name="footer" testProps="子组件的值">
          <h3>没传footer插槽</h3>
        </slot>
    <footer>
  </div>
</template>

<style scoped>
div{
 border: 1px solid #000;  
}
</style>

2.父组件中在使用时:

slot属性弃用,具名插槽通过指令参数v-slot:插槽名 的形式传入,可以简化为 #插槽名

slot-scope属性弃用,作用域插槽通过v-slot:xxx="slotProps"的slotProps来获取子组件传出的属性

v-slot属性只能在<template>上使用,但在【只有默认插槽时】可以在组件标签上使用

javascript 复制代码
//Parent
<template>
  <child>
   <!--默认插槽-->
   <template v-slot>  
     <div>默认插槽</div>
   </template>
   <!--具名插槽-->
   <template #header>
     <div>具名插槽</div>
   </template>
   <!--作用域插槽-->
   <template #footer="slotProps">
     <div>
      {{slotProps.testProps}}
     </div>
   </template>
  <child>
</template>

上一篇笔记关于vue基础应用详解:Vue基本使用

本文引用如下:

slot详解,slot、slot-scope和v-slot

Vue2.x组件间通信汇总表

相关推荐
漫天转悠2 小时前
Vue3项目中引入TailwindCSS(图文详情)
vue.js
qq_589568103 小时前
Echarts+vue电商平台数据可视化——后台实现笔记
vue.js·信息可视化·echarts
5hand4 小时前
Element-ui的使用教程 基于HBuilder X
前端·javascript·vue.js·elementui
GDAL4 小时前
vue3入门教程:ref能否完全替代reactive?
前端·javascript·vue.js
z千鑫4 小时前
【前端】详解前端三大主流框架:React、Vue与Angular的比较与选择
前端·vue.js·react.js
苹果醋36 小时前
React系列(八)——React进阶知识点拓展
运维·vue.js·spring boot·nginx·课程设计
王小王和他的小伙伴6 小时前
解决 vue3 中 echarts图表在el-dialog中显示问题
javascript·vue.js·echarts
好名字08217 小时前
前端取Content-Disposition中的filename字段与解码(vue)
前端·javascript·vue.js·前端框架
隐形喷火龙7 小时前
element ui--下拉根据拼音首字母过滤
前端·vue.js·ui
Simaoya9 小时前
【vue】css模拟玻璃球体效果(带高光)
前端·css·vue.js