inheritAttrs、vm.$listeners 、vm.$attrs 详解

inheritAttrs

组件的根元素是否继承不被认作 props的特性,默认true

//父组件
<template>
   <div>
     <child-dom
      :foo="foo"
      :coo="coo"
     >
     </child-dom>
   </div>
</template>
<script>
   import childDom from "../components/Father2-Child";
   export default {
     data() {
        return {
          foo:"Hello, world",
          coo:"Hello,rui"
        }
     },
     components:{childDom},
   }
</script>
//子组件
<template>
   <div>
      <p>foo:{{foo}}</p>
   </div>
</template>
<script>
export default {
 name:'child-dom',
 props:["foo"],
}
</script>

查看DOM结构,结构如下


因为子组件中没有prop为coo这个属性,所以继承了父组件的特性,如果在子组件的props里接收coo则DOM中就不会有这个属性

在2.4中新增选项inheritAttrs inheritAttrs的默认值为true, 将inheritAttrs的值设为false, 这些默认的行为会禁止掉。

//子组件
<template>
   <div>
      <p>foo:{{foo}}</p>
   </div>
</template>
<script>
export default {
 name:'child-dom',
 props:["foo"],
 inheritAttrs:false,
}
</script>
子组件加了inheritAttrs:false,就不会继承父组件的特性了

但是通过实例属性vm.$attrs ,可以将这些特性生效,且可以通过v-bind 绑定到子组件的非根元素上。

vm.$attrs

//父组件
<template>
   <div>
     <child-dom
      :foo="foo"
      :coo="coo"
     >
     </child-dom>
   </div>
</template>
<script>
   import childDom from "../components/Father2-Child";
   export default {
     data() {
        return {
          foo:"Hello, world",
          coo:"Hello,rui"
        }
     },
     components:{childDom},
   }
</script>
//子组件
<template>
   <div>
      <p>foo:{{foo}}</p>
      <p>attrs:{{$attrs}}</p>
      <childDomChild v-bind="$attrs"></childDomChild>
   </div>
</template>
<script>
import childDomChild from '../components/Father2-Child-Child';
export default {
 name:'child-dom',
 props:["foo"],
 inheritAttrs:false,
 components:{childDomChild}
}
</script>
//孙子组件
<template>
  <div>
   <p>coo:{{coo}}</p>
  </div>
</template>
<script>
  export default {
    name:'childDomChild',
    props:["coo"],
    inheritAttrs:false
  }
</script>
输出结果:子组件和孙子组件通过$attrs获取到父组件的特性

综上所述:可以通过$attrs属性将父组件的数据传递给子组件、孙子组件

注意:
$attrs仅包含了父作用域中不作为 prop 被识别的特性 (class 和 style 除外)

那么问题来了,孙子组件的信息怎么同步给父组件呢?下面我们就来解决这个问题

vm.$listeners

vue2.4版本新增了$listeners属性,它是一个对象,里面包含了作用在这个组件上的所有监听器,有了这个$listeners属性,你就可以配合 v-on="$listeners"将所有的事件监听器指向这个组件的某个特定的子元素。

我们在子组件上 绑定v-on=”$listeners”, 就可以在父组件中监听孙子组件触发的事件,就能把孙子组件发出的数据,传递给父组件。

//父组件
<template>
 <div>
    {{coo}}
   <child-dom
    :foo="foo"
    :coo="coo"
     @upRocket="reciveRocket">
   </child-dom>
 </div>
</template>
<script>
 import childDom from "../components/Father2-Child";
 export default {
   name:'demoNo',
   data() {
        return {
            foo:"Hello, world",
            coo:"Hello,rui"
        }
    },
    components:{childDom},
    methods:{
        reciveRocket(ev){
            this.coo = ev;//改变数据
            console.log(this.coo)
        }
    }
}
</script>
//子组件
<template>
    <div>
        <p>foo:{{foo}}</p>
        <p>attrs:{{$attrs}}</p>
        <childDomChild v-bind="$attrs" v-on="$listeners"></childDomChild>
    </div>
</template>
<script>
import childDomChild from '../components/Father2-Child-Child';
export default {
    name:'child-dom',
    props:["foo"],
    inheritAttrs:false,
    components:{childDomChild}
}
</script>
//孙子组件
<template> 
    <div>
    <p>coo:{{coo}}</p>
    <button @click="startUpRocket">我要发射火箭</button>
    </div>
</template>
<script>
 export default {
    name:'childDomChild',
    props:['coo'],
    methods:{
        startUpRocket(){
            this.$emit("upRocket",'简单我的简单');
        }      
    }
 }
</script>
输出结果

点击“我要发射火箭”后的结果

至此,孙子组件向父组件传递数据的问题也解决了

综上所述:vm.$attrsvm.$listeners 可以解决“父组件”和“子组件”、“孙子组件”、“曾孙子组件”等后代组件的通讯问题

  • inheritAttrs

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

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

  • vm.$attrs

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

  • vm.$listeners

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,904评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,581评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,527评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,463评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,546评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,572评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,582评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,330评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,776评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,087评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,257评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,923评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,571评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,192评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,436评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,145评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,127评论 2 352

推荐阅读更多精彩内容