当前位置: 首页 > news >正文

Vue——组件间数据访问方式与通信方式的一点总结思考

任何事物都有其两面性,以下很多API的优点在某些场景下同时也是缺点。

目录

  • 常态数据访问方式
    • props
      • 适用场景
      • 优点
      • 缺点
      • Demo
    • $attrs
      • 适用场景
      • 优点
      • 缺点
      • Demo
    • provide/inject
      • 适用场景
      • 优点
      • 缺点
      • Demo
    • $refs
      • 适用场景
      • 优点
      • 缺点
      • 个人不推荐使用refs
    • $parent, $children
      • $parent
      • $children
      • 适用场景
      • 优点
      • 缺点
  • 事件通信
    • v-on/$emit
      • 适用场景
      • 优点
      • 缺点
    • v-on/$listener
      • 适用场景
      • 优点
      • 缺点
      • Demo
    • EventBus
      • 适用场景
      • 优点
      • 缺点
      • Demo

常态数据访问方式

props

将数据以变量参数形式传递给子组件中定义的props

官方文档解释
在这里插入图片描述

适用场景

父组件将数据向子组件同步

优点

  • 父组件数据变化会向下传递,子组件中的数据也会跟随变化
  • 复杂数据类型的内部数据变化也可以向下传递

缺点

  • 子组件中直接修改数据会报错,需要使用sync修饰符以及$emit("update$propName$")
  • 如果组件之间隔代过多会导致中间每一层组件都需要定义props

Demo

<Son :age="age">
export default {
	props: {
		age: {
			type: Number
		}
	}
}

$attrs

使用v-bind将未在props中声明的参数数据向下传递

官方文档限定类型与特性
在这里插入图片描述

适用场景

父组件数据向子组件传递,爷爷组件向孙子组件传递,直系组件更多层的嵌套传递

优点

  • 无视组件嵌套层级
  • 有效减少多层组件嵌套场景里中间层组件的props数量

缺点

  • 数据只能用于访问取值,无法修改源数据。
this.$attrs.age = 100;
console.log(this.$attrs.age)		// 100
console.log(this.age);		// 65

在子组件中直接对this.$attrs下的age属性做赋值操作会改变this.$attrs.age的值,但是作为数据来源的祖辈组件中的源数据不受影响

Demo

多层嵌套时,中间层的每层组件都需要加上v-bind="$attrs"

<Parent :gender="gender" :age="age" v-bind="$attrs"/>

provide/inject

依赖注入时使用,即在祖先组件中,加个数据声明为依赖,放入provide中,在其后代组件里使用inject注入依赖,以访问祖先组件内的数据

官方文档给出的类型限制
在这里插入图片描述

适用场景

组件嵌套多层时向下传递数据的场景

优点

  • 无视组件嵌套层级
  • 若依赖声明时为js的基本类型数据,则注入的依赖数据是静态的,声明的祖辈组件内修改或注入的子代组件内修改是互不干扰的

缺点

  • 如果需要使祖辈组件的数据变化动态向下传递,及响应式数据,需要在声明依赖时使用函数,子代组件注入依赖时也需要使用computed或者watch来获取响应变化的数据同时子代组件的修改不会向上传递

Demo

参考我的另一篇博文:传送门

$refs

官方解释:
ref 被用来给元素或子组件注册引用信息。引用信息将会注册在父组件的 $refs 对象上。如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素。

简单来说就是vue里进行dom操作时要用的。

适用场景

  • 需要直接访问或修改子组件数据或方法时
  • 子组件为固定个数,因为使用v-for的场景下,refs取出来的会是数组,当循环渲染多个子组件实例时,未必能稳定取到自己想要的实例

优点

  • 简单粗暴,自由度高,想访问或修改的子组件数据都可以直接操作
  • 层数不多的情况下甚至可以链式调用直接访问孙子组件的数据和方法

缺点

  • 会让数据流向不明晰,出现逻辑bug或数据错误时难以定位
  • 使用时有硬性要求,需要该元素在页面上渲染完成,否则容易报错,所以通常写在nextTick里,或使用前进行判空
  • $refs 也不是响应式的,因此你不应该试图用它在模板中做数据绑定

个人不推荐使用refs

虽然使用很方便,但是这种直接访问或修改子代组件数据和方法的工具,从某种程度上破坏了组件的隔离性,个人更建议所有组件的数据修改都在方法中定义接口以供其他组件通信调用。

但是,使用起来真的很方便,用过一次就会上瘾

$parent, $children

$parent

$parent指向组件的组将的上一层Vue实例

注意:是指向包裹上一层的Vue实例,如果组件外还包裹多层组件库布局标签,例如el-row,el-col。这时候,$parent就不能指向父组件实例。

在这里插入图片描述
在这里插入图片描述
当组件上一层就是父组件时,$parent才能指向父组件实例
在这里插入图片描述
在这里插入图片描述
当Son组件外包裹其他Vue实例时,$parent指向的是上一层的el-col的Vue实例。使用链式调用可以访问到父组件的实例,如下;
this.$parent.$parent.$parent

注意:直接覆盖赋值$parent的属性会改变源数据

$children

$children指向组件内的所有vue子实例(不仅仅是自定义组件,也包括引用的组件库,如Element UI),数据结构始终是数组,即使只有一条数据。
在这里插入图片描述
在这里插入图片描述
可以看到,el-button也是vue实例,所以$children的数组里有2条数据。但是中间的div并不是vue实例,所以没有计入。

注意:修改$children里的实例属性会影响源数据

适用场景

父子组件访问数据;3层或以上会形成链式调用,不推荐

优点

  • 无需在标签上做数据绑定或事件监听,可以直接访问父子组件实例
  • 可以便捷的修改源数据

缺点

  • 层数过多时的链式调用并不优雅
  • 直接修改源数据会导致数据流向不明,当数据造成错误时难以定位

事件通信

v-on/$emit

v-on是给元素添加自定义事件监听的指令,事件可以通过$emit触发,监听的回调函数会读取触发时传入的参数

适用场景

父子组件之间做事件触发或监听,隔代组件或更多层组件嵌套不推荐

优点

  • 语法简单,便于使用,父组件监听子组件事件简单
  • 携带参数便捷

缺点

  • 多级组件嵌套时事件传递需逐层冒泡,中间发生数据变更时溯源不便

v-on/$listener

包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on="$listeners" 传入内部组件——在创建更高层次的组件时非常有用

适用场景

隔代组件进行事件监听或触发时使用

优点

  • 无视组件嵌套层级,在进行复杂关系组件间的事件监听时更灵活自由,不必以冒泡的形式逐层传递

缺点

  • 使用过程中可能不小心就定义了重名事件导致重写父组件事件,或者导致事件重复触发的问题

Demo

<GrandPa @testListeners="testListeners" />

<!-- 隔了多代组件 -->

<Son v-on="$listeners" />

<script>
this.$emit("testListeners")	// son组件中可直接使用$emit触发事件
</script>

EventBus

使用事件总线来管理添加所有的监听事件与接收事件触发消息

适用场景

多层级,多同级,复杂族谱关系的组件之间互相通信并监听事件的情况

优点

  • 无视组件族谱关系,使用独立的Vue实例做事件的注册和消息收发管理
  • 便于溯源管理

缺点

  • 某个组件发送的事件触发消息所有注册事件的组件都会收到,所以不允许出现重名事件,否则会出现错乱导致难以溯源

Demo

  • 使用单独js文件注册空的Vue实例作为事件总线
    // event-bus.js
    import Vue from 'vue'
    export const EventBus = new Vue();
    
  • 在需要注册监听的组件中引入eventbus
    // component1.vue
    import {EventBus} from "event-bus.js";
    // 通常在moounted钩子中使用
    EventBus.$on("demo", (params)=>{ this.demo(params)});
    
  • 在需要触发事件的组件中引入eventbus
    // component2.vue
    import {EventBus} from "event-bus.js";
    EventBus.$emit("demo", params);
    

相关文章:

  • git-错误合并或错误删除文件并推送如何回退
  • 面试——常用的设计模式
  • VUE全局使用element-ui组件
  • express创建项目
  • React脚手架搭建及react项目新建
  • React路由的使用
  • vue跳转带参数---【购物商城项目】(2020.3.13)
  • HTML5新增的标签及属性
  • CSS的透明度处理
  • JS获取节点
  • js获取屏幕信息
  • vue项目http代理,axios
  • vue状态管理(vuex的简介和五个属性)
  • react学习笔记(一) 图片导入传值事件绑定
  • react学习笔记(二) 循环渲染组件+传参
  • 【Leetcode】104. 二叉树的最大深度
  • Bootstrap JS插件Alert源码分析
  • Create React App 使用
  • Druid 在有赞的实践
  • Effective Java 笔记(一)
  • Facebook AccountKit 接入的坑点
  • Java程序员幽默爆笑锦集
  • Perseus-BERT——业内性能极致优化的BERT训练方案
  • ReactNative开发常用的三方模块
  • 测试开发系类之接口自动化测试
  • 从零到一:用Phaser.js写意地开发小游戏(Chapter 3 - 加载游戏资源)
  • 多线程事务回滚
  • 聚簇索引和非聚簇索引
  • 盘点那些不知名却常用的 Git 操作
  • 融云开发漫谈:你是否了解Go语言并发编程的第一要义?
  • 如何优雅地使用 Sublime Text
  • # 安徽锐锋科技IDMS系统简介
  • # 达梦数据库知识点
  • $.ajax中的eval及dataType
  • (安卓)跳转应用市场APP详情页的方式
  • (八)光盘的挂载与解挂、挂载CentOS镜像、rpm安装软件详细学习笔记
  • (顶刊)一个基于分类代理模型的超多目标优化算法
  • (附源码)计算机毕业设计ssm本地美食推荐平台
  • (六)什么是Vite——热更新时vite、webpack做了什么
  • (论文阅读30/100)Convolutional Pose Machines
  • (亲测有效)解决windows11无法使用1500000波特率的问题
  • (学习日记)2024.02.29:UCOSIII第二节
  • (转)LINQ之路
  • . ./ bash dash source 这五种执行shell脚本方式 区别
  • .gitignore文件—git忽略文件
  • .MyFile@waifu.club.wis.mkp勒索病毒数据怎么处理|数据解密恢复
  • .net mvc actionresult 返回字符串_.NET架构师知识普及
  • .NET MVC、 WebAPI、 WebService【ws】、NVVM、WCF、Remoting
  • @SuppressWarnings注解
  • [ C++ ] STL priority_queue(优先级队列)使用及其底层模拟实现,容器适配器,deque(双端队列)原理了解
  • [ 常用工具篇 ] AntSword 蚁剑安装及使用详解
  • []Telit UC864E 拨号上网
  • [AR]Vumark(下一代条形码)
  • [CSS]CSS 的背景
  • [IE 技巧] 显示/隐藏IE 的菜单/工具栏