Vue vm.$attrs使用場(chǎng)景詳解
1、vm.$attrs簡(jiǎn)介
首先我們來(lái)看下vue官方對(duì)vm.$attrs的介紹:
包含了父作用域中不作為 prop 被識(shí)別 (且獲取) 的特性綁定 (class 和 style 除外)。當(dāng)一個(gè)組件沒(méi)有聲明任何 prop 時(shí),這里會(huì)包含所有父作用域的綁定 (class 和 style 除外),并且可以通過(guò) v-bind="$attrs" 傳入內(nèi)部組件——在創(chuàng)建更高層次的組件時(shí)非常有用。
猛一看有點(diǎn)看不明白....
2、場(chǎng)景介紹
vue中一個(gè)比較令人煩惱的事情是屬性只能從父組件傳遞給子組件。這也就意味著當(dāng)你想向嵌套層級(jí)比較深組件數(shù)據(jù)傳遞,只能由父組件傳遞給子組件,子組件再傳遞給孫子組件...像下面這樣:
<parent-component :passdown="passdown"> <child-component :passdown="passdown"> <grand-child-component :passdown="passdown"> ....
就這樣一層一層的往下傳遞passdown這個(gè)變量,最后才能用{{passdown}}。
假如我們需要傳遞的屬性只有1,2個(gè)還行,但是如果我們要傳遞的有幾個(gè)或者10來(lái)個(gè)的情況,這會(huì)是什么樣的場(chǎng)景,我們會(huì)在每個(gè)組件不停的props,每個(gè)必須寫很多遍。有沒(méi)有其它方便的寫法?有,通過(guò)vuex的父子組件通信,的確這個(gè)是一個(gè)方法,但是還有其它的方法,這個(gè)就是我們要說(shuō)的。通過(guò)inheritAttrs選項(xiàng),以及實(shí)例屬性$attrs
3、實(shí)例:
<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>這是個(gè)h1標(biāo)題{{title}}</div>`,
props:['title'],
data(){
return{
mag:'111'
}
},
created:function(){
console.log(this.$attrs)//注意這里
}
}
}
}
</script>
上邊的代碼,我們?cè)诮M件里只是用了title這個(gè)屬性,massgae屬性我么是沒(méi)有用的,那么下瀏覽器渲染出來(lái)是什么樣呢?如下圖:

我們看到:組件內(nèi)未被注冊(cè)的屬性將作為普通html元素屬性被渲染,如果想讓屬性能夠向下傳遞,即使prop組件沒(méi)有被使用,你也需要在組件上注冊(cè)。這樣做會(huì)使組件預(yù)期功能變得模糊不清,同時(shí)也難以維護(hù)組件的DRY。在Vue2.4.0,可以在組件定義中添加inheritAttrs:false,組件將不會(huì)把未被注冊(cè)的props呈現(xiàn)為普通的HTML屬性。但是在組件里我們可以通過(guò)其$attrs可以獲取到?jīng)]有使用的注冊(cè)屬性,如果需要,我們?cè)谶@也可以往下繼續(xù)傳遞。
如果我們?cè)谧咏M件里設(shè)置 inheritAttrs: false:
components:{
'mytest':{
template:`<div>這是個(gè)h1標(biāo)題{{title}}</div>`,
props:['title'],
inheritAttrs: false,
data(){
return{
mag:'111'
}
},
created:function(){
console.log(this.$attrs)//注意這里
}
}
渲染效果如下:

不繼承的情況.png
補(bǔ)充:說(shuō)一下$attrs的使用
有一個(gè)頁(yè)面由父組件,子組件,孫子組件構(gòu)成,如下:
<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>
上面的代碼在頁(yè)面的效果是如下圖

如果attrs被綁定在子組件childcom上后,我們就可以在孫子組件grandcom里獲取到this.$attrs的值。這個(gè){{$attrs}}的值是父組件中傳遞下來(lái)的props(除了子組件childcom組件中props聲明的)。
記住孫子組件grandcom里獲取到this.$attrs的值是除了子組件childcom聲明的元素!記住是除了子組件childcom聲明的元素!例如上面的代碼我在子組件childcom組件的props里聲明了name,那么我在孫子組件grandcom里獲取到的$attrs就不包含name屬性,那么this.$attrs = { 'age':'30', 'sex':'男'}。
說(shuō)一下$attrs的優(yōu)勢(shì)到底在哪
假如我們要做一個(gè)頁(yè)面,有父組件,子組件,孫子組件,如下:
<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的值通過(guò)props傳遞到子組件,子組件在通過(guò)props把a(bǔ)ge的值傳遞到孫子組件,到這里看明白了吧,孫子組件需要的age在子組件里沒(méi)有用到,但是為了能讓孫子組件獲取到,你必須從父組件 傳到子組件,在在子組件傳遞到孫子組件。
但是用$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屬性外所有由父組件傳遞下來(lái)的屬性。如果孫子組件也想獲取到name屬性那么,在綁定個(gè)name如下,
<grandcom v-bind="$attrs" :name="name"></grandcom>
細(xì)細(xì)體會(huì)下是不是這個(gè)道理。實(shí)在不行的話敲一敲代碼自己試驗(yàn)下,你就會(huì)豁然開(kāi)朗。
補(bǔ)充一下:inheritAttrs屬性
關(guān)于inheritAttrs這個(gè)屬性跟獲取到$attrs的值沒(méi)有關(guān)系,inheritAttrs通常在編寫基礎(chǔ)組件時(shí)候會(huì)用到。官網(wǎng)原話:默認(rèn)情況下父作用域的不被認(rèn)作 props 的特性綁定 (attribute bindings) 將會(huì)“回退”且作為普通的 HTML 特性應(yīng)用在子組件的根元素上。當(dāng)撰寫包裹一個(gè)目標(biāo)元素或另一個(gè)組件的組件時(shí),這可能不會(huì)總是符合預(yù)期行為。通過(guò)設(shè)置 inheritAttrs 到 false,這些默認(rèn)行為將會(huì)被去掉。而通過(guò) (同樣是 2.4 新增的) 實(shí)例屬性 $attrs 可以讓這些特性生效,且可以通過(guò) v-bind 顯性的綁定到非根元素上。
注意:這個(gè)選項(xiàng)不影響 class 和 style 綁定。
在Vue2.4.0之前版本,組件內(nèi)未被注冊(cè)的屬性將作為普通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>
上面代碼你覺(jué)得input上會(huì)怎么顯示? 父組件傳遞了type="text",子組件里input 上type="number",那渲染到頁(yè)面會(huì)是什么樣?渲染圖如下:

默認(rèn)情況.png
看到?jīng)],父組件傳遞的type="text"覆蓋了input 上type="number",這豈不是把我的input數(shù)據(jù)類型都給改變了,這豈不是有問(wèn)題,這不是我想要的?。。?!看到這里明白了嗎?回頭去體會(huì)下上面官網(wǎng)的原話?。。?/p>
需求:我需要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>
頁(yè)面渲染圖如下:

需求.png
到這,我想大家都明白了inheritAttrs的作用了吧。默認(rèn)情況下vue會(huì)把父作用域的不被認(rèn)作 props 的特性綁定 且作為普通的 HTML 特性應(yīng)用在子組件的根元素上。綁定就綁定,顯示就顯示,沒(méi)啥大不了的,但是怕就怕遇到一些特殊的,就比如上面的input的情況,這個(gè)時(shí)候inheritAttrs:false的作用就出來(lái)啦。
順道補(bǔ)充一下:$listeners
父組件-子組件-孫子組件,,,,現(xiàn)在我要你在孫子組件里改變父組件的值,怎么改?有很多方法啦,但是$listeners給我們提供了一個(gè)新的思路。話不多說(shuō),直接上代碼
<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>
頁(yè)面渲染如下:

$listeners可以讓你在孫子組件改變父組件的值,是不是很方便............
到此這篇關(guān)于vm.$attrs使用場(chǎng)景詳解的文章就介紹到這了,更多相關(guān)vm.$attrs使用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue在table表中懸浮顯示數(shù)據(jù)及右鍵菜單
這篇文章主要為大家詳細(xì)介紹了vue在table表中懸浮顯示數(shù)據(jù)及右鍵菜單,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-04-04
手把手教你Vue3?按需引入?Echarts的過(guò)程(收藏)
新項(xiàng)目采用?Vue3?作為前端項(xiàng)目框架,避免不了要使用?echarts,但是在使用的時(shí)候,出現(xiàn)了與?Vue2?使用不一樣的地方,所以特別記下來(lái),希望給到有需要的同學(xué)一些幫助2023-10-10
vue項(xiàng)目動(dòng)態(tài)渲染input,綁定的參數(shù)不實(shí)時(shí)更新問(wèn)題
這篇文章主要介紹了vue項(xiàng)目動(dòng)態(tài)渲染input,綁定的參數(shù)不實(shí)時(shí)更新問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-03-03
VUE+Element實(shí)現(xiàn)增刪改查的示例源碼
這篇文章主要介紹了VUE+Element實(shí)現(xiàn)增刪改查的示例源碼,幫助大家更好的理解和使用vue,感興趣的朋友可以了解下2020-11-11
Vue3+Element+Ts實(shí)現(xiàn)表單的基礎(chǔ)搜索重置等功能
本文主要介紹了Vue3+Element+Ts實(shí)現(xiàn)表單的基礎(chǔ)搜索重置等功能,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-12-12
Vue.js中用v-bind綁定class的注意事項(xiàng)
關(guān)于數(shù)據(jù)綁定一個(gè)常見(jiàn)需求就是操作元素的class列表和它的內(nèi)聯(lián)樣式。因?yàn)樗鼈兌际菍傩?,我們可以?v-bind 處理它們,但是使用v-bind綁定class的時(shí)候我們要有一些注意事項(xiàng),下面這篇文章就給大家分享了下要注意的方面,希望能對(duì)大家有所幫助,下面來(lái)一起看看吧。2016-12-12
使用sessionStorage解決vuex在頁(yè)面刷新后數(shù)據(jù)被清除的問(wèn)題
localStorage沒(méi)有時(shí)間期限,除非將它移除,sessionStorage即會(huì)話,當(dāng)瀏覽器關(guān)閉時(shí)會(huì)話結(jié)束,有時(shí)間期限,具有自行百度。本文使用的是sessionStorage解決vuex在頁(yè)面刷新后數(shù)據(jù)被清除的問(wèn)題,需要的朋友可以參考下2018-04-04
vue+echarts定時(shí)重新繪制以達(dá)到刷新的動(dòng)效問(wèn)題
這篇文章主要介紹了vue+echarts定時(shí)重新繪制以達(dá)到刷新的動(dòng)效問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-06-06

