Vue v2.4中新增的$attrs及$listeners属性使用教程


Posted in Javascript onJanuary 08, 2018

前言

多级组件嵌套需要传递数据时,通常使用的方法是通过vuex。如果仅仅是传递数据,而不做中间处理,使用 vuex 处理,未免有点杀鸡用牛刀。Vue 2.4 版本提供了另一种方法,使用 v-bind=”$attrs”, 将父组件中不被认为 props特性绑定的属性传入子组件中,通常配合 interitAttrs 选项一起使用。之所以要提到这两个属性,是因为两者的出现使得组件之间跨组件的通信在不依赖 vuex 和事件总线的情况下变得简洁,业务清晰。

首先分析以下应用场景:

Vue v2.4中新增的$attrs及$listeners属性使用教程

A 组件与 B 组件之间的通信: (父子组件)

如上图所示,A、B、C三个组件依次嵌套,按照 Vue 的开发习惯,父子组件通信可以通过以下方式实现:

  • A to B 通过props的方式向子组件传递,B to A 通过在 B 组件中 $emit, A 组件中 v-on 的方式实现
  • 通过设置全局Vuex共享状态,通过 computed 计算属性和 commit mutation的方式实现数据的获取和更新,以达到父子组件通信的目的。
  • Vue Event Bus,使用Vue的实例,实现事件的监听和发布,实现组件之间的传递。

往往数据在不需要全局的情况而仅仅是父子组件通信时,使用第一种方式即可满足。

A 组件与 C 组件之间的通信: (跨多级的组件嵌套关系)

如上图,A 组件与 C 组件之间属于跨多级的组件嵌套关系,以往两者之间如需实现通信,往往通过以下方式实现:

  • 借助 B 组件的中转,从上到下props依次传递,从下至上,$emit事件的传递,达到跨级组件通信的效果
  • 借助Vuex的全局状态共享
  • Vue Event Bus,使用Vue的实例,实现事件的监听和发布,实现组件之间的传递。

很显然,第一种通过props和$emit的方式,使得组件之间的业务逻辑臃肿不堪,B组件在其中仅仅充当的是一个中转站的作用。如使用第二种 Vuex的方式,某些情况下似乎又有点大材小用的意味,(仅仅是想实现组件之间的一个数据传递,并非数据共享的概念)。第三种情况的使用在实际的项目操作中发现,如不能实现很好的事件监听与发布的管理,往往容易导致数据流的混乱,在多人协作的项目中,不利于项目的维护。

$attrs以及$listeners的出现解决的就是第一种情况的问题,B 组件在其中传递props以及事件的过程中,不必在写多余的代码,仅仅是将$attrs以及$listeners向上或者向下传递即可。

示例代码

如下所示:

A组件(App.vue)

<template>
 <div id="app">
 <child1
 :p-child1="child1"
 :p-child2="child2"
 v-on:test1="onTest1" //此处监听了两个事件,可以在B组件或者C组件中直接触发
 v-on:test2="onTest2"> 
 </child1>
 </div>
</template>
<script>
 import Child1 from './Child1.vue';
 export default {
 data () {
 return {};
 },
 components: { Child1 },
 methods: {
 onTest1 () {
 console.log('test1 running...');
 },
 onTest2 () {
 console.log('test2 running');
 }
 }
 };
</script>

B组件(Child1.vue)

<template>
 <div class="child-1">
 <p>in child1:</p>
 <p>props: {{pChild1}}</p>
 <p>$attrs: {{$attrs}}</p>
 <hr>
 <!-- C组件中能直接触发test的原因在于 B组件调用C组件时 使用 v-on 绑定了$listeners 属性 -->
 <!-- 通过v-bind 绑定$attrs属性,C组件可以直接获取到A组件中传递下来的props(除了B组件中props声明的) -->
 <child2 v-bind="$attrs" v-on="$listeners"></child2>
 </div>
</template>
<script>
 import Child2 from './Child2.vue';
 export default {
 props: ['pChild1'],
 data () {
 return {};
 },
 inheritAttrs: false,
 components: { Child2 },
 mounted () {
 this.$emit('test1');
 }
 };
</script>

结果:

in child1:

props: v_child1

$attrs: { “p-child2”: “v_child2”}

C 组件 (Child2.vue)

<template>
 <div class="child-2">
 <p>in child2:</p>
 <p>props: {{pChild2}}</p>
 <p>$attrs: {{$attrs}}</p>
 <hr>
 </div>
</template>
<script>
 export default {
 props: ['pChild2'],
 data () {
 return {};
 },
 inheritAttrs: false,
 mounted () {
 this.$emit('test2');
 }
 };
</script>

结果:

in child2:

props: v_child2

$attrs: {}

知识点总结

$attrs

 包含了父作用域中不被认为 (且不预期为) props 的特性绑定 (class 和 style 除外)。当一个组件没有声明任何 props 时,这里会包含所有父作用域的绑定 (class 和 style 除外),并且可以通过 v-bind=”$attrs” 传入内部组件——在创建更高层次的组件时非常有用。

$listeners

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

inheritAttrs

默认情况下父作用域的不被认作 props 的特性绑定 (attribute bindings) 将会“回退”且作为普通的 HTML 特性应用在子组件的根元素上。当撰写包裹一个目标元素或另一个组件的组件时,这可能不会总是符合预期行为。通过设置 inheritAttrs 到 false,这些默认行为将会被去掉。而通过 (同样是 2.4 新增的) 实例属性 $attrs 可以让这些特性生效,且可以通过 v-bind 显性的绑定到非根元素上。

上述特性的使用完全可以降低在不使用Vuex以及事件总线的情况下,组件跨级props以及事件传递的复杂度。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

Javascript 相关文章推荐
JavaScript页面刷新与弹出窗口问题的解决方法
Mar 02 Javascript
关于二级域名下使用一级域名下的COOKIE的问题
Nov 07 Javascript
基于jquery的代码显示区域自动拉长效果
Dec 07 Javascript
了解jQuery技巧来提高你的代码(个人觉得那个jquery的手册很不错)
Feb 10 Javascript
jquery 扑捉回车键事件代码
Apr 24 Javascript
Javascript仿新浪游戏频道鼠标悬停显示子菜单效果
Aug 21 Javascript
js关于getImageData跨域问题的解决方法
Oct 14 Javascript
JS开发中基本数据类型具体有哪几种
Oct 19 Javascript
红黑树的插入详解及Javascript实现方法示例
Mar 26 Javascript
vue-awesome-swiper 基于vue实现h5滑动翻页效果【推荐】
Nov 08 Javascript
使用vuepress搭建静态博客的示例代码
Feb 14 Javascript
node koa2 ssr项目搭建的方法步骤
Dec 11 Javascript
实例解析ES6 Proxy使用场景介绍
Jan 08 #Javascript
详解weex默认webpack.config.js改造
Jan 08 #Javascript
关于vue单文件中引用路径的处理方法
Jan 08 #Javascript
浅谈React Native Flexbox布局(小结)
Jan 08 #Javascript
Node.js使用Koa搭建 基础项目
Jan 08 #Javascript
JavaScript体验异步更好的解决办法
Jan 08 #Javascript
探索Vue高阶组件的使用
Jan 08 #Javascript
You might like
教大家制作简单的php日历
2015/11/17 PHP
php中使用websocket详解
2016/09/23 PHP
php无限级分类实现方法分析
2016/10/19 PHP
PHP使用finfo_file()函数检测上传图片类型的实现方法
2017/04/18 PHP
Yii2选项卡的简单使用
2017/05/26 PHP
JQuery插件fancybox无法在弹出层使用左右键的解决办法
2013/12/25 Javascript
在myeclipse中如何加入jquery代码提示功能
2014/06/03 Javascript
jquery常用操作小结
2014/07/21 Javascript
JS控制弹出新页面窗口位置和大小的方法
2015/03/02 Javascript
详解AngularJS Filter(过滤器)用法
2015/12/28 Javascript
javascript简单比较日期大小的方法
2016/01/05 Javascript
BootStrap Table 获取同行不同列元素的方法
2016/12/19 Javascript
基于React实现表单数据的添加和删除详解
2017/03/14 Javascript
es6学习笔记之Async函数的使用示例
2017/05/11 Javascript
深入浅析javascript继承体系
2017/10/23 Javascript
react-native 实现购物车滑动删除效果的示例代码
2021/01/15 Javascript
[44:51]2018DOTA2亚洲邀请赛 4.4 淘汰赛 VP vs Liquid 第二场
2018/04/05 DOTA
[52:14]VG vs Serenity 2018国际邀请赛小组赛BO2 第一场 8.17
2018/08/20 DOTA
python模块之time模块(实例讲解)
2017/09/13 Python
Python pymongo模块用法示例
2018/03/31 Python
在cmd命令行里进入和退出Python程序的方法
2018/05/12 Python
Python二叉树定义与遍历方法实例分析
2018/05/25 Python
Python3.4 tkinter,PIL图片转换
2018/06/21 Python
Python可迭代对象操作示例
2019/05/07 Python
Django中自定义查询对象的具体使用
2019/10/13 Python
python爬取股票最新数据并用excel绘制树状图的示例
2021/03/01 Python
HTML5 新标签全部总汇(推荐)
2016/06/13 HTML / CSS
英国玛莎百货美国官网:Marks & Spencer美国
2018/11/06 全球购物
TheFork葡萄牙:欧洲领先的在线餐厅预订平台
2019/05/27 全球购物
北京麒麟网信息技术有限公司网络游戏测试面试题
2013/09/28 面试题
广播电视新闻学专业应届生求职信
2013/10/08 职场文书
2014年国培研修感言
2014/03/09 职场文书
辩论赛开场白大全(主持人+辩手)
2015/05/29 职场文书
读书笔记怎么写
2015/07/01 职场文书
CSS 实现Chrome标签栏的技巧
2021/08/04 HTML / CSS
python编程简单几行代码实现视频转换Gif示例
2021/10/05 Python