Vue3兄弟,爷孙组件间传值【包含手撸发布/订阅类】

Vue2【Vue基础十】— 兄弟组件之间传值【中央事件总线,消息订阅与发布】
Vue2 : 【Vue基础九】–父子组件传值

一、 兄弟组件

1-1 事件总线

  • 使用Vue3,会发现,原本得心应手的eventBus突然不灵了
  • Vue3不再提供$on与emit函数,Vue实例不再实现事件接口。官方推荐引入外部工具实现,或者自己手撸一个事件类

1-1-1 使用EventBus

  1. 引入/编写事件库
  2. 在入口文件中挂载
  3. 在组件中引入并使用

1-1-2 不借助插件的原生使用方式

  1. 引入/编写事件库

    • 方法一: 引入官方推荐的mitt
    • 方法二: 手撸一个简单的发布/订阅类
      // eventBus.js
      export default class EventBus{
              
              
          constructor(){
              
              
              this.events = {
              
              };
          }
          emit(eventName, data) {
              
              
              if (this.events[eventName]) {
              
              
                  this.events[eventName].forEach(function(fn) {
              
              
                      fn(data);
                  });
              }
          }
          on(eventName, fn) {
              
              
              this.events[eventName] = this.events[eventName] || [];
              this.events[eventName].push(fn);
          }
      
          off(eventName, fn) {
              
              
              if (this.events[eventName]) {
              
              
                  for (var i = 0; i < this.events[eventName].length; i++) {
              
              
                      if (this.events[eventName][i] === fn) {
              
              
                          this.events[eventName].splice(i, 1);
                          break;
                      }
                  };
              }
          }
      }
      
  2. 在入口文件main.js中执行挂载

// main.js
import {
    
     createApp } from 'vue'
import App from './App.vue'
// ① 引入事件类
// 自己编写的或者mitt皆可
import EventBus from 'lib/bus.js'
// 或者:import EventBus from 'mitt'
const $bus = new EventBus()

// ② 挂载
// 1.使用provide提供
app.provide('$bus', $bus)
// 2.挂载到this上
app.config.globalProperties.$bus = $bus
  1. 在组件中引入并使用
    • 在creates中使用
    // Button.vue
    export default {
          
          
      created() {
          
          
          this.$bus.emit('ButtonCreated')
      }
    }
    
    • 在setup中使用

    注意: 因为在setup中无法访问到应用实例(this),如果你需要在setup中使用eventBus,则需要通过provide/inject方式引入

    // Button.vue
    import {
          
           inject } from 'vue'
    export default {
          
          
      setup() {
          
          
          const $bus = inject('$bus')
          $bus.emit('ButtonSetup')
      }
    }
    

二、 爷孙组件

2-1 props和$emit

最常用的父子组件通信方式,爷爷–> 父 ----> 子

1、 父组件向子组件传递数据是通过prop传递的,子组件传递数据给父组件是通过$emit触发事件做到的
2、 处理父子组件之间的数据传输有一个问题:

  • 多层嵌套,父组件A下面有子组件B,组件B下面有组件C,A想传递给C怎么办?
  • 采用第一种方法,必须让组件A通过prop传递消息给组件B,组件B再传给C
  • Vue2.4之后,引入了attrs和listeners来解决这个问题

2-2 attrs和listeners

1、 attrs和listeners的过程:

父组件A下面有子组件B,组件B下面有组件C,组件A传递数据给组件B

  • C组件
Vue.component('C', {
    
    
	template: `
	 <div> 
     	<input type="text" v-model="$attrs.messageC" @input="passCData($attrs.messageC)"> 
     </div>
	`,
	methods: {
    
    
		passCData(val) {
    
    
			// 触发父组件A中的事件
			this.$emit('getCData',val)
		}
	}
})
  • B组件
Vue.component('B', {
    
    
	data() {
    
    
		return {
    
    
			myMessage: this.message
		}
	},
	template: `
	<div> 
		 <input type="text" v-model="myMessage" @input="passData(myMessage)"> 
		 <C v-bind="$attrs" v-on="$listeners"></C> 
	</div> 	
	`
	// 得到父组件传递过来的数据
	props: ['message'],
	methods: {
    
    
		passData(val) {
    
    
			// 触发父组件中的事件
			this.$emit('getChildData',val)
		}
	}
})
  • A组件
Vue.component('A',{
    
    
	template: `
		 <div> 
			 <p>this is parent compoent!</p> 
			 <B  
			 :messageC="messageC"  
			 :message="message"  
			 v-on:getCData="getCData"  
			 v-on:getChildData="getChildData(message)"> 
			 </B> 
		</div> 
	`,
	data() {
    
    
		return {
    
    
			message: 'Hello',
			messageC: 'Hello c'
		}
	},
	methods: {
    
    
		getChildData(val) {
    
    
			console.log('这是来自B组件的数据')
		},
		// 执行C子组件触发的事件
		getCData(val) {
    
    
			console.log("这是来自C组建的数据:"+val)
		}
	}
})
var app = new Vue({
    
    
	el: '#app',
	template: `
		<div><A></A></div>
	`
})

2、 解析:

  • C组件中能直接触发getData的原因: B组件调用C组件时,使用v-on绑定了$listeners属性
  • 通过v-bind绑定$attrs属性,C组件可以直接获取到A组件中传递下来的props(除了B组件中props声明的)

三、 v-model

1、 父组件通过v-model传递值给子组件时,会自动传递一个value的prop属性,在子组件中通过this.$emit(‘input’,val)自动修改v-model绑定的值

后续回来得看看

  • https://blog.csdn.net/m0_56986233/article/details/121405388
  • https://www.zhihu.com/question/466846675

猜你喜欢

转载自blog.csdn.net/hannah2233/article/details/128544881