Vue中组件的通信方式-以及nextTick分析

1. 前言

vue也是组件化开发框架,对于这种组件化开发来说,组件之间的通信方式通常都是非常重要的
所以单独开一个篇章来总结下有哪些通信方式


2. 首先列出常用的组件通信方式

1.props
2.$emit/$on
3.$children/$parent
4.$attrs / $listeners
5.ref
6.$root
7.eventBus
8.vuex

列出来后,可以自己先考虑下应用场景

下面不饶弯子了,以组件的关系来解说通信方式


3. 父子组件通信

3.1 props 父传子

1.父组件以属性的方式传值给子组件
2.子组件通过props方式接收数据

3.1.1父组件核心代码

在父组件中引入子组件并绑定parentData自定义属性





3.1.2 子组件核心代码

1.在子组件中使用 props 接收父组件传递的数据,
2.props 里的名字跟父组件定义的属性名一致




Vue的单向数据流机制,子组件不能够直接去修改父组件传递的修改的,否则能改的话那父组件的值就被污染了。

但是子组件内想要修改父组件传过来的值却不“污染”父组件的话,
可以在子组件内定义一个变量mydata去接收parentData数据,并使用 watch 监听parentData数据的变更


3.2 $emit/$on 子传父

1.子组件绑定自定义事件
2.使用 $emit() 触发更改数据

3.2.1 子组件核心代码

告诉父组件我要更改数据啦



3.2.2父组件核心代码

1.父组件定义并绑定子组件传递的triggerEmit事件
2.triggerEmit事件名需跟子组件 $emit() 的事件名





3.3 $parent/$children

1.子组件通过 $parent 获得父组件实例

2.父组件通过 $children 获得子组件实例数组

3.3.1 子组件




this.$parent可以获取到父组件的方法、data的数据等,并可以直接使用和执行。


3.3.2 父组件





3.3.3 注意钩子的使用

父组件是在 mounted()生命周期中获取子组件实例的,并且获取的实例是一个数组形式


3.3.4 问题 层级发生变化的时候咋办呢 ???

1.源码其实有更高层次的封装,在引用parent到时候抽象一个更高级的方法类似 dispatch,
2.直接指定比较重要的父组件的类型或者名称,在循环查找的时候避免程序的脆弱性


3.4 ref

父组件使用 $refs 获得组件实例





1.注意 钩子 mounted

  1. 父组件就可以直接使用this.$refs.xx获取子组件的实例

3.5 $attrs/$listeners


4. 兄弟组件

核心就是找共同点, 搭建桥梁,中间人,话事人的感觉

4.1 $parent

既然是兄弟往上找 总能找到共同的祖先
不常用,可以参考文章上面 的 写法


4.2 $root

其实 根也是共享的


4.3 eventBus 也是都可以访问的

4.3.1 创建一个Vue实例

作为调度中心 eventBus

import Vue from "vue"
export default new Vue()

4.3.2 需要进行通信的组件中 引入


import { EventBus } from "../bus.js"
export default{
  data(){
    return{}
  },
  methods:{
    changeName(){
      EventBus.$emit("editName", '俺的小破站')
    }
  }
}


4.3.3 监听事件


import { EventBus } from "../bus.js"
export default{
  data(){
    return{}
  },
  mounted:{
    EventBus.$on('editName',(name)=>{
      console.log(name) // 俺的小破站!
    })
  }
}


4.4 vuex

具体可以看我之前写的vuex-0系列


5. 跨级组件

5.1eventBus


5.2 vuex

1.相当于一个公共数据的仓库
2.提供一些方法管理仓库数据
3.具体可以看我之前写的vuex-0系列


5.3.provide/inject

5.3.1 简介

父组件使用 provide 注入数据
子组件使用 inject 使用数据


5.3.2 父组件
export default{
 provide: {
   return{
     provideName: '俺的小破站'
   }
 }
}

5.3.3 分析

provideName这个变量可以提供给它其下的所有子组件,包括曾孙、孙子组件等,只需要使用 inject 就能获取数据


5.3.4 子组件
export default{
  inject: ['provideName'],
  created () {
    console.log(this.provideName) // 俺的小破站
  }
}

5.3.5 优缺点

1.父组件不需要知道哪个组件使用它提供出去的数据
2.子组件不需要知道这个数据从哪里来
3.更加的原生,不会对第三方库产生依赖

缺点:单向的;只能祖辈向子辈传值


6.vue3 通信方式

6.1 props和emit

setup函数可以接受两个参数, prop 和 context ,其中context可以解构出emit slots attrs
利用 emit实例来传参


6.2 子组件 代码





6.3 简要分析

Vue3this的概念了,所以就不会有this.$emit存在,
所以可以从setup传入的context解构出emit实例,从而派发事件给父组件


6.4 父组件





7. ref

Vue3我们可以从Vue中导出 ref 方法,得到子组件的实例

7.1 分析

1.通过,在子组件声明ref属性,
2.属性值必须和const btnRef = ref(null)这里声明的变量名一致,否则会报错
3.拿到子组件实例后就可以直接调用组件的sendParent方法了


7.2 父组件代码



这里使用的btnRef.value?.是可选链操作符语法,
代表?前面的值为true才继续执行后面的语句


7.3 使用




8. provide/inject

和vue2差不离儿

8.1 父组件




8.2 子组件



子孙组件使用inject获取到父组件注入的数


8.3 区别

其实主要就是 Vue3采用了 这个模块化
所以inject 和 provide 需要单独导入


9. nextTick 是什么

在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。

官方案例

// 修改数据
vm.msg = 'Hello'
// DOM 还没有更新
Vue.nextTick(function () {
  // DOM 更新了
})

// 作为一个 Promise 使用 (2.1.0 起新增,详见接下来的提示)
Vue.nextTick()
  .then(function () {
    // DOM 更新了
  })

10.为什么 需要nextTick

由于vue的异步更新策略导致我们对数据的修改不会立刻体现在dom变化上,此时如果想要立即获取更新后的dom状态,就需要使用这个方法

vue在更新DOM时是异步执行的.只要侦听到数据变化,vue将开启一个队列,并缓冲在同一事件循环中发生的所有数据变更.如果同一个watcher被多次触发,只会会被推入到队列中1次.
这种在缓冲时取出重复数据对于避免不必要的计算和DOM操作是非常重要的.
nextTick方法会在队列中加入一个回调函数,确保该函数在前面的DOM 操作完成后才调用

所以当我们想在数据修改后立即看到都DOM执行结果就需要用到nextTick方法


11. 源码分析

主要就是通过 callbacks 回调函数的数组,存的就是nextTick传的函数,
使用函数 timerFunc通过异步机制调用


参考资料

attrs $listeners 传值
proviede inject 传值
vuex-0系列


初心

我所有的文章都只是基于入门,初步的了解;是自己的知识体系梳理;
如果能帮助到有缘人,非常的荣幸,一切为了部落的崛起;
共勉

你可能感兴趣的:(Vue中组件的通信方式-以及nextTick分析)