Vue vm.$attrs使用场景详解


Posted in Javascript onMarch 08, 2020

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属性我么是没有用的,那么下浏览器渲染出来是什么样呢?如下图:

Vue vm.$attrs使用场景详解

我们看到:组件内未被注册的属性将作为普通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)//注意这里
   }
  }

渲染效果如下:

Vue vm.$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>

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

Vue vm.$attrs使用场景详解

如果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",那渲染到页面会是什么样?渲染图如下:

Vue vm.$attrs使用场景详解

默认情况.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>

页面渲染图如下:

Vue vm.$attrs使用场景详解

需求.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>

页面渲染如下:

Vue vm.$attrs使用场景详解

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

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

Javascript 相关文章推荐
鼠标滑在标题上显示图片的JS代码
Nov 19 Javascript
js中使用replace方法完成某个字符的转换
Aug 20 Javascript
js实现网页标题栏闪烁提示效果实例分析
Nov 20 Javascript
常见的javascript跨域通信方法
Dec 31 Javascript
内容滑动切换效果jquery.hwSlide.js插件封装
Jul 07 Javascript
html+javascript+bootstrap实现层级多选框全层全选和多选功能
Mar 09 Javascript
jq checkbox 的全选并ajax传参的实例
Apr 01 Javascript
微信小程序外卖选购页实现切换分类与数量加减功能案例
Jan 15 Javascript
vue+element模态框中新增模态框和删除功能
Jun 11 Javascript
vue draggable resizable gorkys与v-chart使用与总结
Sep 05 Javascript
JavaScript工具库MyTools详解
Jan 01 Javascript
JavaScript十大取整方法实例教程
Dec 03 Javascript
浅谈Vue2.4.0 $attrs与inheritAttrs的具体使用
Mar 08 #Javascript
vue-cli点击实现全屏功能
Mar 07 #Javascript
vue全屏事件开发详解
Jun 17 #Javascript
vue实现全屏滚动效果(非fullpage.js)
Mar 07 #Javascript
vue项目使用高德地图的定位及关键字搜索功能的实例代码(踩坑经验)
Mar 07 #Javascript
详解钉钉小程序组件之自定义模态框(弹窗封装实现)
Mar 07 #Javascript
Vue实现手机扫描二维码预览页面效果
May 28 #Javascript
You might like
在字符串中把网址改成超级链接
2006/10/09 PHP
PHP If Else(elsefi) 语句
2013/04/07 PHP
php实现购物车功能(以大苹果购物网为例)
2017/03/09 PHP
PHP结合Ffmpeg快速搭建流媒体服务的实践记录
2018/10/31 PHP
对象无length属性时IE6/IE7中无法将其转换成伪数组(ArrayLike)
2011/07/31 Javascript
javascript之典型高阶函数应用介绍
2013/01/10 Javascript
JavaScript将相对地址转换为绝对地址示例代码
2013/07/19 Javascript
JS实现点击按钮控制Div变宽、增高及调整背景色的方法
2015/08/05 Javascript
js 基础篇必看(点击事件轮播图的简单实现)
2016/08/20 Javascript
使用vue实现点击按钮滑出面板的实现代码
2017/01/10 Javascript
微信小程序 video详解及简单实例
2017/01/16 Javascript
three.js中文文档学习之创建场景
2017/11/20 Javascript
关于单文件组件.vue的使用
2018/09/20 Javascript
浅谈关于iview表单验证的问题
2018/09/29 Javascript
微信小程序实现时间预约功能
2018/11/27 Javascript
Javascript 对象(object)合并操作实例分析
2019/07/30 Javascript
教你如何用Node实现API的转发(某音乐)
2019/09/20 Javascript
结合axios对项目中的api请求进行封装操作
2020/09/21 Javascript
Vue 打包的静态文件不能直接运行的原因及解决办法
2020/11/19 Vue.js
Vue过滤器,生命周期函数和vue-resource简单介绍
2021/01/12 Vue.js
[02:32]DOTA2亚洲邀请赛 C9战队出场宣传片
2015/02/07 DOTA
python使用reportlab画图示例(含中文汉字)
2013/12/03 Python
归纳整理Python中的控制流语句的知识点
2015/04/14 Python
举例讲解Python的Tornado框架实现数据可视化的教程
2015/05/02 Python
python机器学习案例教程——K最近邻算法的实现
2017/12/28 Python
Python将DataFrame的某一列作为index的方法
2018/04/08 Python
Python闭包函数定义与用法分析
2018/07/20 Python
英国著名的化妆品折扣网站:Allbeauty.com
2016/07/21 全球购物
英国儿童家具专卖店:GLTC
2016/09/24 全球购物
学生生病请假条范文
2014/02/16 职场文书
影子教师研修方案
2014/06/14 职场文书
计算机应用专业自荐信
2014/07/05 职场文书
幼儿园家长反馈意见
2015/06/03 职场文书
二婚主持词
2015/06/30 职场文书
小学四年级班务总结该怎么写?
2019/08/16 职场文书
nginx如何将http访问的网站改成https访问
2021/03/31 Servers