Vue组件通信的常用方案(超级全面!!!)

2 篇文章 0 订阅
2 篇文章 0 订阅

1.props

父组件向子组件传值(这个不必多说,不了解的朋友可以去Vue官网补下基础)

2.$emit

子组件向父组件传值(这个不必多说)

3.ref

(1)ref简介

ref可以用在dom元素和组件实例上,两种情况有些差别。应用在dom元素上获取的是真实的dom元素,应用在组件上获取的则是组件实例对象。

(2)示例代码

  //父组件
 <template>
     <div>
         <child ref="child"></child>
     </div>
  </template>
  <script>
     import child from "./child.vue";
     export default {
         methods: {
             getList(){
                 this.$refs.child.init()
             }
         }
     }
  <script/>
  //子组件
   <template>
      <div></div>
   </template>
    <script>
       export default {
       methods: {
       init(){
          console.log('获取列表')
        }
      }
     }
   <script/>

(3)弊端

  • 破坏了单向数据流的原则
    Vue中的单向数据流原则一定要弄清楚,简单来说就是数据应该是单向流动的,即从父组件向子组件流动。直接使用$ref在父组件修改子组件内的数据,这可能导致之后再维护和排错时候出现麻烦(可以细细体会)。

  • 导致组件复用困难
    使用$refs之后,只能把父子组件绑定在一块了。这违背了组件复用的某些原则,让组件复用的效果不是太好。

4.children

children的用法和ref用法很相似,有点不同的是children是一个数组,包含所有子组件对象。下面我写一个示例代码:

  this.$children[0].func1(); // 我是子组件1
  this.$children[1].func2();  //我是子组件2

5.parent

通过$parent,子组件可以调用父组件的方法或者使用子组件的数据(与ref类似)。

6.root

$root 属性指向 Vue 实例的根实例。在 Vue 组件树中,每个组件都可以通过 $root 访问到根实例,从而实现跨层级的通信和数据共享(不用多说)。

7.attrs和listeners

(1)作用

  • attrs:包含了父作用域中不被认为 (且不预期为) props 的特性绑定 (class 和 style 除外),并且可以通过 v-bind=”$attrs” 传入内部组件。当一个组件没有声明任何 props 时,它包含所有父作用域的绑定 (class 和 style 除外)。
  • listeners:包含了父作用域中的 (不含 .native 修饰符) v-on 事件监听器。它可以通过 v-on=”$listeners” 传入内部组件。它是一个对象,里面包含了作用在这个组件上的所有事件监听器,相当于子组件继承了父组件的事件。

(2)使用场景

常常用于组件库二次封装。我举个例子:我要在原有的el-button第三方组件的基础上实现“hover提示并且点击按钮出现弹框”的功能,同时保证其原有的功能。
在父组件中:接收子组件,向子组件传递数据(参数)和定义自定义事件

//父组件
<template>
  <div>
    <h2>hover属性的按钮</h2>
    <!-- 在使用封装的按钮时,向子组件传递相应的参数 -->
    <!-- @click代表的是自定义事件 -->
    <hintButton icon="el-icon-plus" size="mini" type="success" title="wanglm" @click="handler"></hintButton>
  </div>
</template>
<script>
//引入子组件
import hintButton from '@/components/hintButton.vue'
export default {
  name: 'app',
  //注册
  components: {
    hintButton
  },
  methods: {
    handler() {
      alert('wanglm666')
    }
  }
}
</script>
<style></style>

在子组件中,通过v-bind接收父组件传递的数据,通过v-on可以获取到父组件给子组件传递自定义事件。

//子组件
<template>
  <div>
    <!-- 可以使用a标签实现按钮带有提示功能 -->
    <a :title="title">
      <el-button v-bind="$attrs" v-on="$listeners"></el-button>
    </a>
  </div>
</template>

<script>
export default {
  name: 'hintButton',
  props: ['title'],
  mounted() {
    console.log('this.$attrs', this.$attrs)
    console.log('this.$listeners', this.$listeners)
  }
}
</script>
<style></style>

在实际的组件库二次封装中,可能第三方组件会有很多参数,在这样子的嵌套结构中,经常用到上述方法巧妙地解决麻烦。

8.provide和inject

(1)作用

祖先组件通过provide传递数据给子孙组件,子孙组件通过inject接受数据。

(2)示例代码

  //祖先组件
  provide(){
    return{
      sendCount:this.count
    }
   }
  //子孙组件
  inject:['sendCount'],

和props用法有点类似。

9.全局事件总线

(1)安装总线

const vm = new Vue({
    el: '#root',
    ...
    beforeCreate() {
        Vue.prototype.$eventbus = this;
        //这里this是vue实例,它本身是已经实现了bus的功能(当然也实现了与bus无关的其它功能)
        //也可自己写一个bus类
        //Vue.prototype.$eventbus = new customBus();
    }
})

(2)订阅数据

  //接收数据的组件
  mounted() {
    this.$bus.$on('sendParams', function(params){
       console.log('接收到的参数', params);
    });
  },

(3)发布数据

  //发送数据的组件
 <button @click="$bus.$emit('sendParams', 25)">发送数据</button>

10.vuex

(1)与事件总线有何不同

vuex是统一管理,事件总线不是集中管理,各组件都能emit,都能on接收,显得有点乱。

(2)原理图

在这里插入图片描述
我就不详细讲述vuex的原理及其使用了,不太熟悉的朋友可以参考vuex官网,其实内容也是比较简单的,后续可能考虑花一期把vuex讲透。

11.slot

插槽也是可以通信的。我就简单列举一下,插槽是个比较简单的概念。

(1) 默认插槽

(2) 具名插槽

//子组件
<template>
   <slot> </slot>
   <slot name="content"></slot>
</template>
//父组件
<child>
   <template v-slot:default> </template>
   <!-- 具名插槽用插槽名做参数-->
   <template v-slot:content> ...</template>
</child>

(3) 作用域插槽

//子组件
<template>
   <slot name="footer" testProps="111">
       <h3>footer</h3>
   </slot>
</template>
//父组件
<child>
 <template v-slot:default="slotProps">
   {{slotProps.testProps}}
 </template>
 <template #default="slotProps">
   {{slotProps.testProps}}
 </template>
</child>

12.第三方库

比如Pubsub,大家可以研究研究它的源码,里面用到了发布订阅模式。

(1) 安装

  npm i pubsub-js

(2) 订阅数据

在接收数据的组件,绑定事件(订阅消息),留下回调,接收参数。

  Pubsub.subscribe('changeMessage', this.changeMessage)

(3) 发布数据

在传递数据的组件,触发事件(发布消息),传递参数。

  Pubsub.publish('changeMessage')

可以发现Pubsub和事件总线极其相似,唯一的区别在接收数据的函数中,参数一是消息类型。

13.手写Bus

(1) 定义Bus类

//自定义中央事件总线(Vue中是默认已经实现了$bus的功能)---下面的实现我是从Vue双向数据绑定底层原理那受到了启发
export class Bus {
    constructor() {
        this.callbacks = {}//存放事件,每个事件属性又都是一个对象,存放当前事件的所有回调
        this.callbackEventId = 0;//每次自增
    }
    $on(name, fn) {
        this.callbacks[name] = this.callbacks[name] || {};
        this.callbacks[name][++this.callbackEventId] = fn;
        return this.callbackEventId;
    }
    $emit(name, ...args) {
        for (let id in this.callbacks[name]) {
            this.callbacks[name][id](...args)
        }
    }
    $off(name, id = undefined) {
        if (id == undefined) {// 如果只提供了name参数,则只会移除该事件相关的监听器;
            delete this.callbacks[name]
        } else {// 如果同时提供了name和id 参数,则只会移除指定事件及回调函数的监听器。
            delete this.callbacks[name][id]
            if (Object.keys(this.callbacks[name]).length == 0) {
                delete this.callbacks[name]
            }
        }
    }
    //清空所有的监听器
    $offs() {
        this.callbacks = {};
    }
}

(2) 使用Bus类

 const vm = new Vue({
        el: '#root',
        components: {
            'wlm-student': student,
            'wlm-school': school
        },
        data: {},
        created() {
        },
        mounted() {
        },
        methods: {
        },
        beforeCreate() {
            Vue.prototype.$eventbus = new Bus();
        }
    })
  • 21
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值