手機編程軟件有哪些谷歌網(wǎng)站推廣優(yōu)化
目錄
透傳 Attributes
Attributes 繼承?
對?class?和?style?的合并
v-on?監(jiān)聽器繼承
深層組件繼承?
禁用 Attributes 繼承?
多根節(jié)點的 Attributes 繼承?
vue2?$attrs 和 $listeners?
$attrs 概念說明
$attrs 案例
$listeners?概念說明
$listeners案例
?vue3 $attrs 和 $listeners?
?attrs在 template 中的用法
只有1個根元素的情況下
有2個根元素的情況下
$listeners??棄用
?attrs在 js 中的用法
Options API
Composition API 3.0的語法?
Composition API 3.2的語法?
總結(jié)
移除?$listeners?
概覽
2.x 語法
3.x 語法
$attrs?包含?class?&?style?
概覽
2.x 行為?
3.x 行為
(1)$props:當(dāng)前組件接收到的 props 對象。Vue 實例代理了對其 props 對象屬性的訪問。
(2)$attrs:包含了父作用域中不作為 prop?被識別 (且獲取) 的特性綁定 (class 和 style 除外)。
(3)$listeners:包含了父作用域中(不含 .native 修飾器的)v-on事件監(jiān)聽器。他可以通過 v-on="listeners"傳入內(nèi)部組件
透傳 Attributes
透傳 Attributes?是指由父組件傳入,且沒有被子組件聲明為 props 或是組件自定義事件的 attributes 和事件處理函數(shù)。
Attributes 繼承?
“透傳 attribute”指的是傳遞給一個組件,卻沒有被該組件聲明為?props?或?emits?的 attribute 或者?v-on
?事件監(jiān)聽器。最常見的例子就是?class
、style
?和?id
。
當(dāng)一個組件以單個元素為根作渲染時,透傳的 attribute 會自動被添加到根元素上。舉例來說,假如我們有一個?<MyButton>
?組件,它的模板長這樣:
<!-- <MyButton> 的模板 -->
<button>click me</button>
一個父組件使用了這個組件,并且傳入了?class
:
<MyButton class="large" />
最后渲染出的 DOM 結(jié)果是:
<button class="large">click me</button>
?這里,<MyButton>
?并沒有將?class
?聲明為一個它所接受的 prop,所以?class
?被視作透傳 attribute,自動透傳到了?<MyButton>
?的根元素上。
對?class
?和?style
?的合并
如果一個子組件的根元素已經(jīng)有了?class
?或?style
?attribute,它會和從父組件上繼承的值合并。如果我們將之前的?<MyButton>
?組件的模板改成這樣:
<!-- <MyButton> 的模板 -->
<button class="btn">click me</button>
?則最后渲染出的 DOM 結(jié)果會變成:
<button class="btn large">click me</button>
v-on
?監(jiān)聽器繼承
同樣的規(guī)則也適用于?v-on
?事件監(jiān)聽器
<MyButton @click="onClick" />
click
?監(jiān)聽器會被添加到?<MyButton>
?的根元素,即那個原生的?<button>
?元素之上。當(dāng)原生的?<button>
?被點擊,會觸發(fā)父組件的?onClick
?方法。同樣的,如果原生?button
?元素自身也通過?v-on
?綁定了一個事件監(jiān)聽器,則這個監(jiān)聽器和從父組件繼承的監(jiān)聽器都會被觸發(fā)。
深層組件繼承?
有些情況下一個組件會在根節(jié)點上渲染另一個組件。例如,我們重構(gòu)一下?<MyButton>
,讓它在根節(jié)點上渲染?<BaseButton>
:
<!-- <MyButton/> 的模板,只是渲染另一個組件 -->
<BaseButton />
此時?<MyButton>
?接收的透傳 attribute 會直接繼續(xù)傳給?<BaseButton>
。
請注意:
透傳的 attribute 不會包含?
<MyButton>
?上聲明過的 props 或是針對?emits
?聲明事件的?v-on
?偵聽函數(shù),換句話說,聲明過的 props 和偵聽函數(shù)被?<MyButton>
“消費”了。透傳的 attribute 若符合聲明,也可以作為 props 傳入?
<BaseButton>
。
禁用 Attributes 繼承?
如果你不想要一個組件自動地繼承 attribute,你可以在組件選項中設(shè)置?inheritAttrs: false
。
最常見的需要禁用 attribute 繼承的場景就是 attribute 需要應(yīng)用在根節(jié)點以外的其他元素上。通過設(shè)置?inheritAttrs
?選項為?false
,你可以完全控制透傳進來的 attribute 被如何使用。
vue2?
Vue 2 的虛擬 DOM 實現(xiàn)對?
class
?和?style
?attribute 有一些特殊處理。因此,與其它所有 attribute 不一樣,它們沒有被包含在?$attrs
?中。上述行為在使用?
inheritAttrs: false
?時會產(chǎn)生副作用:
$attrs
?中的 attribute 將不再被自動添加到根元素中,而是由開發(fā)者決定在哪添加。- 但是?
class
?和?style
?不屬于?$attrs
,它們?nèi)匀粫粦?yīng)用到組件的根元素中:
<template><label><input type="text" v-bind="$attrs" /></label>
</template>
<script>
export default {inheritAttrs: false
}
</script>
vue3
從 3.3 開始你也可以直接在?<script setup>
?中使用?defineOptions:
<script setup>
defineOptions({inheritAttrs: false
})
// ...setup 邏輯
</script>
這些透傳進來的 attribute 可以在模板的表達式中直接用?$attrs
?訪問到。
<span>Fallthrough attribute: {{ $attrs }}</span>
這個?$attrs
?對象包含了除組件所聲明的?props
?和?emits
?之外的所有其他 attribute,例如?class
,style
,v-on
?監(jiān)聽器等等。
有幾點需要注意:
和 props 有所不同,透傳 attributes 在 JavaScript 中保留了它們原始的大小寫,所以像?
foo-bar
?這樣的一個 attribute 需要通過?$attrs['foo-bar']
?來訪問。像?
@click
?這樣的一個?v-on
?事件監(jiān)聽器將在此對象下被暴露為一個函數(shù)?$attrs.onClick
。
多根節(jié)點的 Attributes 繼承?
和單根節(jié)點組件有所不同,有著多個根節(jié)點的組件沒有自動 attribute 透傳行為。如果?$attrs
?沒有被顯式綁定,將會拋出一個運行時警告。
<CustomLayout id="custom-layout" @click="changeValue" />
如果?<CustomLayout>
?有下面這樣的多根節(jié)點模板,由于 Vue 不知道要將 attribute 透傳到哪里,所以會拋出一個警告。
<header>...</header>
<main>...</main>
<footer>...</footer>
如果?$attrs
?被顯式綁定,則不會有警告:
<header>...</header>
<main v-bind="$attrs">...</main>
<footer>...</footer>
vue2?$attrs 和 $listeners?
$attrs 概念說明
- 包含了父作用域中
不作為 prop 被識別 (且獲取) 的 attribute 綁定 (class 和 style 除外)
- $attrs 包含了傳遞給一個組件的 attribute 名和 attribute 值;即一個JSON對象
- 可以通過
v-bind="$attrs"
傳入內(nèi)部組件
$attrs 案例
父組件
<template><SlotContainerref="slotContainer"name="huangbiao":isOk="false":option="{ a: 1, b: true, c: 'ddd' }"></SlotContainer>
</template><script>
import SlotContainer from "./SlotContainer"export default {data() {return {};},components: {SlotContainer,}
};
</script><style lang="scss" scoped></style>
子組件
<script>
export default {data() {return {};},props: {option: {type: Object,default: function() {return {};}}},mounted() {console.log(this.$attrs);},methods: {}
};
</script>
結(jié)果
不注釋掉子組件的props, $attrs的值
注釋掉子組件的props, $attrs的值
inheritAttrs: false 和 $attrs ;配合使用解決的問題??
- 可以手動決定這些 attribute 會被賦予哪個元素
- inheritAttrs: false 選項不會影響 style 和 class 的綁定
- 這個模式允許你在使用基礎(chǔ)組件的時候更像是使用原始的 HTML 元素,而不會擔(dān)心哪個元素是真正的根元素
$listeners?概念說明
- 包含了
父作用域中的 (不含 .native 修飾器的) v-on 事件監(jiān)聽器
。 - 可以配合?
v-on="$listeners" 將所有的事件監(jiān)聽器指向這個組件的某個特定的子元素
- 它是一個對象,里面包含了作用在這個組件上的所有監(jiān)聽器。
$listeners案例
<template><div class><SlotContainerref="slotContainer"v-on:m1="m1"v-on:m2="m2"@m3="m3"@m4="m4"@click.native="testJiami"></SlotContainer></div>
</template><script>
import SlotContainer from "./SlotContainer";
import CryptoJS from "crypto-js";
export default {data() {return {};},components: {SlotContainer,},methods: {testJiami() {this.m1();this.m2();this.m3();this.m4();},m1() {console.log("加密結(jié)果一 MD5:" + CryptoJS.MD5("你好"));// 加鹽 對應(yīng)的APIconsole.log("加密結(jié)果一 MD5:" + CryptoJS.HmacMD5("你好", "salt"));console.log(CryptoJS.SHA256("123456").toString());// 加鹽 對應(yīng)的APIconsole.log(CryptoJS.HmacSHA256("123456", "salt").toString());},m2() {var pwd = "passwor";console.log("加密結(jié)果二 Hmac-MD5: " + CryptoJS.HmacMD5("你好", pwd));},m3() {var salt = CryptoJS.enc.Utf8.parse("salt"); //鹽var iter = 1000; //迭代次數(shù)var mi = CryptoJS.PBKDF2("你好", salt, {keySize: parseInt(4),iterations: parseInt(iter),});console.log("加密結(jié)果三:" + mi);},m4() {var pswd = "我的密碼";var mi = CryptoJS.AES.encrypt("你好", pswd);console.log("加密結(jié)果四" + mi);//解密var result = CryptoJS.AES.decrypt(mi, pswd).toString(CryptoJS.enc.Utf8);console.log("解密結(jié)果:" + result);},},
};
</script><style lang="scss" scoped></style>
子組件(SlotContainer.vue)
<script>
export default {data() {return {};},mounted() {console.log(this.$listeners);},methods: {}
};
</script><style lang="scss" scoped></style>
結(jié)果
@click.native="testJiami"的方法沒有在 $listeners中
?vue3 $attrs 和 $listeners?
簡單來說, attrs 主要接收沒在 props 里定義,但父組件又傳過來的屬性。
<!-- 父組件 ParentCom.vue -->
<template><ChildCommsg="雷猴"data="123"/>
</template><script setup>
import ChildCom from './ChildCom.vue'
</script><!-- 子組件 ChildCom.vue -->
<template><div>{{ msg }} - {{ $attrs }}</div>
</template><script setup>
defineProps({msg: {type: String}
})
</script>
可以看到,在子組件中,msg 使用了 props 接收,所以 {{ msg }} 可以直接輸出 props 里接收的內(nèi)容。
而沒在 props 里接收的內(nèi)容,全部都放到了 $attrs 里,并且存在一個對象里面。
接下來將展開講解不同情況下 attrs 的使用方法。
?attrs在 template 中的用法
在前面簡單的例子里其實已經(jīng)大概知道 attrs 在 template 的用法。但 Vue3 中 template 不再要求只有一個根元素了。所以 attrs 在 template 中分2種情況使用。
只有1個根元素的情況下
只有1個根元素的情況下,子組件中,沒被 props 接收的屬性,都會綁定在根元素上。
<!-- 父組件 ParentCom.vue -->
<template><ChildCommsg="雷猴"data="123"name="鯊魚辣椒"style="color: red;"/>
</template><script setup>
import ChildCom from './ChildCom.vue'
</script><!-- 子組件 ChildCom.vue -->
<template><div>{{ msg }}</div>
</template><script setup>
defineProps({msg: {type: String}
})
</script>
可以看到,沒被 props 接收的屬性都被綁定到根元素上了。
連 style 里傳入的樣式也被執(zhí)行,文字變成紅色了。
有2個根元素的情況下
當(dāng)子組件有2個根元素時,沒被 props 接收的屬性不會綁定到子組件的元素上。
<!-- 父組件 ParentCom.vue -->
<template><ChildCommsg="雷猴"data="123"name="鯊魚辣椒"style="color: red;"/>
</template><script setup>
import ChildCom from './ChildCom.vue'
</script><!-- 子組件 ChildCom.vue -->
<template><div>{{ msg }}</div><div>{{ msg }}</div>
</template><script setup>
defineProps({msg: {type: String}
})
</script>
?
此時連父組件傳入是 style 樣式都不生效了。
如果我們此時希望第二個元素綁定所有沒被 props 接收的屬性,可以使用 v-bind="$attrs" 的方法實現(xiàn)
<!-- 父組件 ParentCom.vue -->
<template><ChildCommsg="雷猴"data="123"name="鯊魚辣椒"style="color: red;"/>
</template><script setup>
import ChildCom from './ChildCom.vue'
</script><!-- 子組件 ChildCom.vue -->
<template><div>{{ msg }}</div><div v-bind="$attrs">{{ msg }}</div>
</template><script setup>
defineProps({msg: {type: String}
})
</script>
?
$listeners??棄用
$listeners
?對象在 Vue 3 中已被移除。事件監(jiān)聽器現(xiàn)在是?$attrs
?的一部分:
{text: '這是一個 attribute',onClose: () => console.log('close 事件被觸發(fā)')
}
?attrs在 js 中的用法
除了在 template 中可以訪問到 $attrs ,在 JS 中也可以訪問到。
vue 3 其實是兼容大部分 Vue 2 語法的,也就是 Options API 。而 attrs 在 Options APi 和 Composition Api 中的使用方法會稍微有一丟丟區(qū)別。而 Composition API 又分為 Vue 3.2 前的語法和 3.2 后的語法。
接下來將分開討論這3種情況。
Options API
<!-- 父組件 ParentCom.vue -->
<template><ChildCommsg="雷猴"data="123"name="鯊魚辣椒"style="color: red;"/>
</template><script setup>
import ChildCom from './ChildCom.vue'
</script><!-- 子組件 ChildCom.vue 暫不關(guān)注 template 部分 -->
<script>
export default {props: {msg: {type: String}},mounted() {console.log(this.$attrs)}
}
</script>
此時控制臺會輸出沒被 props 接收的屬性。?
Composition API 3.0的語法?
<!-- 父組件 ParentCom.vue -->
<template><ChildCommsg="雷猴"data="123"name="鯊魚辣椒"style="color: red;"/>
</template><script setup>
import ChildCom from './ChildCom.vue'
</script><!-- 子組件 ChildCom.vue 暫不關(guān)注 template 部分 -->
<script>
export default {props: {msg: {type: String}},setup(props, context) {console.log('props: ', props)console.log('attrs: ', context.attrs)}
}
</script>
Vue 3.2 前的寫法,需要在 setup 方法里接收2個參數(shù),而 attrs 就在 context 參數(shù)里。
Composition API 3.2的語法?
Vue 3.2 后的語法,可以在 <script> 標(biāo)簽上添加 setup 屬性。所以在代碼里就不需要再調(diào)用 setup 方法了。
在這種情況下,props 成了默認(rèn)的全局方法,而 attrs 則需要另外引入。
<!-- 父組件 ParentCom.vue -->
<template><ChildCommsg="雷猴"data="123"name="鯊魚辣椒"style="color: red;"/>
</template><script setup>
import ChildCom from './ChildCom.vue'
</script><!-- 子組件 ChildCom.vue 暫不關(guān)注 template 部分 -->
<script setup>
import { useAttrs } from 'vue'const props = defineProps({msg: {type: String}
})const attrs = useAttrs()console.log('props: ', props)
console.log('attrs: ', attrs)
</script>
需要引入 vue 中的 useAttrs ,在調(diào)用 useAttrs 后會返回當(dāng)前未被 props 接收的屬性。
重點是以下兩句。
import { useAttrs } from 'vue'
const attrs = useAttrs()
總結(jié)
移除?$listeners
?
概覽
$listeners
?對象在 Vue 3 中已被移除。事件監(jiān)聽器現(xiàn)在是?$attrs
?的一部分:
{text: '這是一個 attribute',onClose: () => console.log('close 事件被觸發(fā)')
}
2.x 語法
在 Vue 2 中,你可以通過?this.$attrs
?訪問傳遞給組件的 attribute,以及通過?this.$listeners
?訪問傳遞給組件的事件監(jiān)聽器。結(jié)合?inheritAttrs: false
,開發(fā)者可以將這些 attribute 和監(jiān)聽器應(yīng)用到根元素之外的其它元素:
<template><label><input type="text" v-bind="$attrs" v-on="$listeners" /></label>
</template>
<script>export default {inheritAttrs: false}
</script>
3.x 語法
在 Vue 3 的虛擬 DOM 中,事件監(jiān)聽器現(xiàn)在只是以?on
?為前綴的 attribute,這樣它就成為了?$attrs
?對象的一部分,因此?$listeners
?被移除了。
<template><label><input type="text" v-bind="$attrs" /></label>
</template>
<script>
export default {inheritAttrs: false
}
</script>
如果這個組件接收一個?id
?attribute 和一個?v-on:close
?監(jiān)聽器,那么?$attrs
?對象現(xiàn)在將如下所示:
{id: 'my-input',onClose: () => console.log('close 事件被觸發(fā)')
}
$attrs
?包含?class
?&?style
?
概覽
$attrs
?現(xiàn)在包含了所有傳遞給組件的 attribute,包括?class
?和?style
。
2.x 行為?
Vue 2 的虛擬 DOM 實現(xiàn)對?class
?和?style
?attribute 有一些特殊處理。因此,與其它所有 attribute 不一樣,它們沒有被包含在?$attrs
?中。
上述行為在使用?inheritAttrs: false
?時會產(chǎn)生副作用:
$attrs
?中的 attribute 將不再被自動添加到根元素中,而是由開發(fā)者決定在哪添加。- 但是?
class
?和?style
?不屬于?$attrs
,它們?nèi)匀粫粦?yīng)用到組件的根元素中:
<template><label><input type="text" v-bind="$attrs" /></label>
</template>
<script>
export default {inheritAttrs: false
}
</script>
像這樣使用時:
<my-component id="my-id" class="my-class"></my-component>
……將生成以下 HTML:
<label class="my-class"><input type="text" id="my-id" />
</label>
3.x 行為
$attrs
?包含了所有的?attribute,這使得把它們?nèi)繎?yīng)用到另一個元素上變得更加容易了?,F(xiàn)在上面的示例將生成以下 HTML:
<label><input type="text" id="my-id" class="my-class" />
</label>
在使用了?
inheritAttrs: false
?的組件中,請確保樣式仍然符合預(yù)期。如果你之前依賴了?class
?和?style
?的特殊行為,那么一些視覺效果可能會遭到破壞,因為這些 attribute 現(xiàn)在可能被應(yīng)用到了另一個元素中。