Vue vm.$attrs使用场景详解

1、vm.$attrs简介

首先我们来看下vue官方对vm.$attrs的介绍:
包含了父作用域中不作为 prop 被识别 (且获取) 的特性绑定 (class 和 style 除外)。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 (class 和 style 除外),并且可以通过 v-bind="$attrs" 传入内部组件——在创建更高层次的组件时非常有用。
猛一看有点看不明白....

2、场景介绍

vue中一个比较令人烦恼的事情是属性只能从父组件传递给子组件。这也就意味着当你想向嵌套层级比较深组件数据传递,只能由父组件传递给子组件,子组件再传递给孙子组件...像下面这样:

<parent-component :passdown="passdown">

<child-component :passdown="passdown">

<grand-child-component :passdown="passdown">

....

就这样一层一层的往下传递passdown这个变量,最后才能用{{passdown}}。

假如我们需要传递的属性只有1,2个还行,但是如果我们要传递的有几个或者10来个的情况,这会是什么样的场景,我们会在每个组件不停的props,每个必须写很多遍。有没有其它方便的写法?有,通过vuex的父子组件通信,的确这个是一个方法,但是还有其它的方法,这个就是我们要说的。通过inheritAttrs选项,以及实例属性$attrs

3、实例:

<template>
 <div class="home">
  <mytest :title="title" :massgae="massgae"></mytest>
 </div>
</template>
<script>
export default {
 name: 'home',
 data () {
  return {
   title:'title1111',
   massgae:'message111'
  }
 },
 components:{
  'mytest':{
   template:`<div>这是个h1标题{{title}}</div>`,
   props:['title'],
   data(){
    return{
     mag:'111'
    }
   },
   created:function(){
    console.log(this.$attrs)//注意这里
   }
  }
 }
}
</script>

上边的代码,我们在组件里只是用了title这个属性,massgae属性我么是没有用的,那么下浏览器渲染出来是什么样呢?如下图:

我们看到:组件内未被注册的属性将作为普通html元素属性被渲染,如果想让属性能够向下传递,即使prop组件没有被使用,你也需要在组件上注册。这样做会使组件预期功能变得模糊不清,同时也难以维护组件的DRY。在Vue2.4.0,可以在组件定义中添加inheritAttrs:false,组件将不会把未被注册的props呈现为普通的HTML属性。但是在组件里我们可以通过其$attrs可以获取到没有使用的注册属性,如果需要,我们在这也可以往下继续传递。

如果我们在子组件里设置 inheritAttrs: false:

components:{
  'mytest':{
   template:`<div>这是个h1标题{{title}}</div>`,
   props:['title'],
   inheritAttrs: false,
   data(){
    return{
     mag:'111'
    }
   },
   created:function(){
    console.log(this.$attrs)//注意这里
   }
  }

渲染效果如下:

不继承的情况.png

补充:说一下$attrs的使用

有一个页面由父组件,子组件,孙子组件构成,如下:

<template>
  <div style="padding:50px;">
    <childcom :name="name" :age="age" :sex="sex"></childcom>
  </div>
</template>
<script>
export default {
  'name':'test',
  props:[],
  data(){
    return {
      'name':'张三',
      'age':'30',
      'sex':'男'
    }
  },
  components:{
    'childcom':{
      template:`<div>
        <div>{{name}}</div>
        <grandcom v-bind="$attrs"></grandcom>
      </div>`,
      props:['name'],
      components: {
        'grandcom':{
          template:`<div>{{$attrs}}</div>`,
        }
      }
    }
  }
}
</script>

上面的代码在页面的效果是如下图

如果attrs被绑定在子组件childcom上后,我们就可以在孙子组件grandcom里获取到this.$attrs的值。这个{{$attrs}}的值是父组件中传递下来的props(除了子组件childcom组件中props声明的)。

记住孙子组件grandcom里获取到this.$attrs的值是除了子组件childcom声明的元素!记住是除了子组件childcom声明的元素!例如上面的代码我在子组件childcom组件的props里声明了name,那么我在孙子组件grandcom里获取到的$attrs就不包含name属性,那么this.$attrs = { 'age':'30', 'sex':'男'}。

说一下$attrs的优势到底在哪

假如我们要做一个页面,有父组件,子组件,孙子组件,如下:

<template>
  <div>
    <childcom></childcom>
  </div>
</template>
<script>
export default {
  'name':'test',
  props:[],
  data(){
    return {
      'name':'张三',
      'age':'30',
      'sex':'男'
    }
  },
  components:{
    'childcom':{
      template:`<div>
        <div>我是子组件</div>
        <grandcom></grandcom>
      </div>`,
      components: {
        'grandcom':{
          template:`<div>我是孙子组件</div>`,
        }
      }
    }
  }
}
</script>

如上代码,假如我想在子组件想获取到父组件的name属性值,在孙子组件获取父组件的age属性值,用props的话就必须在父组件把name和age的值通过props传递到子组件,子组件在通过props把age的值传递到孙子组件,到这里看明白了吧,孙子组件需要的age在子组件里没有用到,但是为了能让孙子组件获取到,你必须从父组件 传到子组件,在在子组件传递到孙子组件。

但是用$attrs就不用那么麻烦,如下:

<template>
  <div>
    <childcom :name="name" :age="age" :sex="sex"></childcom>
  </div>
</template>
<script>
export default {
  'name':'test',
  props:[],
  data(){
    return {
      'name':'张三',
      'age':'30',
      'sex':'男'
    }
  },
  components:{
    'childcom':{
      props:['name'],
      template:`<div>
        <div>我是子组件  {{name}}</div>
        <grandcom v-bind="$attrs"></grandcom>
      </div>`,
      components: {
        'grandcom':{
          template:`<div>我是孙子组件{{$attrs.age}}</div>`,
        }
      }
    }
  }
}
</script>

子组件绑定了"$attrs",孙子组件就能获取到除了name属性外所有由父组件传递下来的属性。如果孙子组件也想获取到name属性那么,在绑定个name如下,

 <grandcom v-bind="$attrs" :name="name"></grandcom>

细细体会下是不是这个道理。实在不行的话敲一敲代码自己试验下,你就会豁然开朗。

补充一下:inheritAttrs属性

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

注意:这个选项不影响 class 和 style 绑定。

在Vue2.4.0之前版本,组件内未被注册的属性将作为普通html元素属性被渲染。

inheritAttrs到底有啥用?到底用在哪里?看下边代码,

<template>
  <childcom :name="name" :age="age" type="text"></childcom>
</template>
<script>
export default {
  'name':'test',
  props:[],
  data(){
    return {
      'name':'张三',
      'age':'30',
      'sex':'男'
    }
  },
  components:{
    'childcom':{
      props:['name','age'],
      template:`<input type="number" style="border:1px solid blue">`,
    }
  }
}
</script>

上面代码你觉得input上会怎么显示? 父组件传递了type="text",子组件里input 上type="number",那渲染到页面会是什么样?渲染图如下:

默认情况.png

看到没,父组件传递的type="text"覆盖了input 上type="number",这岂不是把我的input数据类型都给改变了,这岂不是有问题,这不是我想要的!!!!看到这里明白了吗?回头去体会下上面官网的原话!!!

需求:我需要input 上type="number"类型不变,但是我还是要取到父组件的type="text"的值,那么代码如下:

<template>
  <childcom :name="name" :age="age" type="text"></childcom>
</template>
<script>
export default {
  'name':'test',
  props:[],
  data(){
    return {
      'name':'张三',
      'age':'30',
      'sex':'男'
    }
  },
  components:{
    'childcom':{
      inheritAttrs:false,
      props:['name','age'],
      template:`<input type="number" style="border:1px solid blue">`,
      created () {
        console.log(this.$attrs.type)
      }
    }
  }
}
</script>

页面渲染图如下:

需求.png

到这,我想大家都明白了inheritAttrs的作用了吧。默认情况下vue会把父作用域的不被认作 props 的特性绑定 且作为普通的 HTML 特性应用在子组件的根元素上。绑定就绑定,显示就显示,没啥大不了的,但是怕就怕遇到一些特殊的,就比如上面的input的情况,这个时候inheritAttrs:false的作用就出来啦。

顺道补充一下:$listeners

父组件-子组件-孙子组件,,,,现在我要你在孙子组件里改变父组件的值,怎么改?有很多方法啦,但是$listeners给我们提供了一个新的思路。话不多说,直接上代码

<template>
  <div>
    <childcom :name="name" :age="age" :sex="sex" @testChangeName="changeName"></childcom>
  </div>
</template>
<script>
export default {
  'name':'test',
  props:[],
  data(){
    return {
      'name':'张三',
      'age':'30',
      'sex':'男'
    }
  },
  components:{
    'childcom':{
      props:['name'],
      template:`<div>
        <div>我是子组件  {{name}}</div>
        <grandcom v-bind="$attrs" v-on="$listeners"></grandcom>
      </div>`,

      components: {
        'grandcom':{
          template:`<div>我是孙子组件-------<button @click="grandChangeName">改变名字</button></div>`,
          methods:{
            grandChangeName(){
              this.$emit('testChangeName','kkkkkk')
            }
          }
        }
      }
    }
  },
  methods:{
    changeName(val){
      this.name = val
    }
  }
}
</script>

页面渲染如下:

$listeners可以让你在孙子组件改变父组件的值,是不是很方便............

到此这篇关于vm.$attrs使用场景详解的文章就介绍到这了,更多相关vm.$attrs使用内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

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

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

  • 浅谈Vue2.4.0 $attrs与inheritAttrs的具体使用

    vue父子组件之间的传值我们都知道使用props和emit,但是祖孙之间的传值在以前,我们都需要子辈作为中间人,当祖辈有值要传递给孙辈时,需要子辈作为中间人把值传递给孙辈,当孙辈想要改变祖辈的值时,需要先emit子辈的方法,然后子辈再emit父辈的方法从而改变祖辈的值,如果是多级组件嵌套的话,那么祖孙辈之间传值,就会变得非常的繁琐,为了解决这个需求,vue2.4版本产生了$attrs,$listeners,inheritAttrs这三个属性. vm.$attrs 官方API vm.$attrs

  • vue中通过使用$attrs实现组件之间的数据传递功能

    组件之间传递数据的方式有很多种,之所以有这么多种方式,是为了满足在不同场景不同条件下的使用. 一般有三种方式: props vuex Vue Event Bus 本文介绍的是使用$attrs的方式. 这是$attrs的官网api https://cn.vuejs.org/v2/api/#vm-attrs 这个api是在2.4版本中添加的,那么为什么要添加这个特性呢? 看看官网是怎么解释的 包含了父作用域中不作为 prop 被识别 (且获取) 的特性绑定 ( class  和  style  除外

  • Vue 父子组件数据传递的四种方式( inheritAttrs + $attrs + $listeners)

    当我们在书写 vue 组件的时候,也许可能会用到数据传递:将父组件的数据传递给子组件,有时候也需要通过子组件去事件去触发父组件的事件: 每当我们遇到这样的需求的时候,我们总是会想到有三种解决办法: 通过 props 的方式向子组件传递(父子组件) vuex 进行状态管理(父子组件和非父子组件) vuex 非父子组件的通信传递 Vue Event Bus ,使用Vue的实例,实现事件的监听和发布,实现组件之间的传递. 后来再逛社区的时候我又发现了还有第四种传递方式, inheritAttrs +

  • Vue vm.$attrs使用场景详解

    1.vm.$attrs简介 首先我们来看下vue官方对vm.$attrs的介绍: 包含了父作用域中不作为 prop 被识别 (且获取) 的特性绑定 (class 和 style 除外).当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 (class 和 style 除外),并且可以通过 v-bind="$attrs" 传入内部组件--在创建更高层次的组件时非常有用. 猛一看有点看不明白.... 2.场景介绍 vue中一个比较令人烦恼的事情是属性只能从父组件传递给子组件

  • Vue中provide、inject详解以及使用教程

    目录 Vue中 常见的组件通信方式可分为三类 1. provide / inject 简介 2. provide / inject 使用方法 3. 总结 总结 传送门:Vue中 子组件向父组件传值 及 .sync 修饰符 详解 传送门:Vue中 状态管理器(vuex)详解及应用场景 传送门:Vue中 $ attrs.$ listeners 详解及使用 传送门:Vue中 事件总线(eventBus)详解及使用 传送门:Vue 2.x 官方文档 provide / inject 说明 Vue中 常见

  • Vue常见组件间通信方案及典型应用场景详解

    目录 什么是组件通信 1.父子组件通信场景 2.兄弟组件通信场景 3.根组件和后代组件通信场景 4.插槽通信场景 5 无直接关系的组件通信场景 6 大型项目中的复杂组件通信场景 - Vuex状态管理 7 其他的一些组件通信方案 总结 什么是组件通信 所谓组件通信,就是组件之间的数据交互,也就是把一个组件A里面的数据传递到另一个组件B,并能够让组件B根据这个数据更新界面. 在 Vue中,可用的通信方案有很多,下面给大家描述几个常用的组件通信方案及其典型的应用场景. 1.父子组件通信场景 父子组件通

  • Vue中的vue-resource示例详解

    vue-resource特点 vue-resource插件具有以下特点: 1. 体积小 vue-resource非常小巧,在压缩以后只有大约12KB,服务端启用gzip压缩后只有4.5KB大小,这远比jQuery的体积要小得多. 2. 支持主流的浏览器 和Vue.js一样,vue-resource除了不支持IE 9以下的浏览器,其他主流的浏览器都支持. 3. 支持Promise API和URI Templates Promise是ES6的特性,Promise的中文含义为"先知",Pro

  • 关于vue组件事件属性穿透详解

    组件事件属性穿透 属性 $attrs包含从父组件传过来的属性,但不包含子组件中prop中的属性以及class和style,所以对于那些html元素原生属性,可以不用再子组件中声明,直接从父组件中传进来就好 // 子组件 <template> <div> <input type="text" name="" id="" v-bind="$attrs" v-on='listeners'/> &l

  • vue+VeeValidate 校验范围实例详解(部分校验,全部校验)

    搜索很久,没有发现有关于vue+VeeValidate部分校验的.自己写一个. 主要是两个场景: 1. 校验范围内,所有的字段. 2. 校验全局所有字段. 主要方法: 1.validate(fields, scope) 2. validateAll(fields) 场景: 遍历得到多个列表,每一个列表都可以独立保存当前列表.在保存当前列表的时候,需要校验当前列表输入框的合法性. 代码: <div class=" col-xs-12 col-md-6 col-lg-4" v-for

  • vue总线机制(bus)知识点详解

    vue中非父子组件之间通信除了使用vuex,也可以通过bus总线,两者适用场景不同. bus适合小项目.数据被更少组件使用的项目,对于中大型项目 数据在很多组件之间使用的情况 bus就不太适用了.bus其实就是一个发布订阅模式,利用vue的自定义事件机制,在触发的地方通过$emit向外发布一个事件,在需要监听的页面,通过$on监听事件. vuex适用中大型项目.数据在多组件之间公用的情况. 简单介绍两者的区别之后,就要介绍下我在一个项目中遇到的一个场景了,这个场景使用bus可能更加适合些: //

  • Android Rxjava3 使用场景详解

    目录 一.Rxjava使用场景 1.多任务嵌套回调 2.多任务合并处理 3.轮询 4.其他小场景 1)倒计时 2)打字机效果 二.结合Rxbinding的使用场景 1.点击事件防抖 2.输入搜索优化 3.联合判断 三.防泄漏 1.Observable.unsubscribeOn 2.disposable.dispose 3.CompositeDisposable 参考了以下文章,表示感谢: 一.Rxjava使用场景 为了模拟实际场景,从wanandroid网站找了二个接口,如下:(对Wanand

  • vue实现列表展示示例详解

    目录 Vue 的CSS之deep语法 ::v-deep classPrefix 前缀 给元素绑定class 总结 Object.freeze 关于Vue和ts的配合问题 ISO8601和dayjs库 一. ISO8601 1. Date对象=>ISO字符串 2. ISO字符串=>Date对象 JS操作时间的库-dayjs 安装 使用 JSON.parse的返回值没有类型 Vue 的CSS之deep语法 ::v-deep 我们知道,在Vue组件的style标签里,加上scoped属性,会使写的样

  • Vue面试中observable原理详解

    目录 一.Observable 是什么 二.使用场景 三.原理分析 一.Observable 是什么 Observable 翻译过来我们可以理解成可观察的 我们先来看一下其在Vue中的定义 Vue.observable,让一个对象变成响应式数据.Vue 内部会用它来处理 data 函数返回的对象 返回的对象可以直接用于渲染函数和计算属性内,并且会在发生变更时触发相应的更新.也可以作为最小化的跨组件状态存储器 Vue.observable({ count : 1}) 其作用等同于 new vue(

随机推荐