vue $attrs和$listeners的使用與區別
首先讓我們看一下這張圖,表示瞭一個多級關聯的組件嵌套
為什麼要用$attrs
和 $listeners
先讓我們來想一種情況,就是組件A跟組件C怎麼通信,我們可以有多少中解決方案?
- 看到這種情況,大多數人應該會想到用vuex來進行數據通信吧,但是如果項目中多個組件中的共享狀態很少,且項目比較小,全局數據通信也很少,那我們用vuex來實現這個功能,就感覺有點殺雞用牛刀瞭
- 我們可以使用組件B來做通信的中轉站,當組件A需要把數據傳到組件C時,組件A通過props將數據傳給組件B,然後組件B再用props傳給組件C,這是一種解決方案,但是如果嵌套的組件過多,就會導致代碼冗餘且繁瑣,維護就比較困難,而且如果組件C也要將數據傳給組件A,也要一層一層往上傳遞,就更麻煩瞭
- 自定義一個Vue數據總線,這種適合組件跨級傳遞數據,但是缺點是碰到多人合作時,會導致代碼的維護性較低,代碼可讀性也較低
- 還有一種解決方案,就是用provide inject,但是這種方式,官方不推薦,因為這個方法真的是太不好管控瞭,比如說我在根組件provide瞭this,孫孫重孫組件去使用瞭this裡面的一個變量,這時候很難去跟蹤到這個變量的出處瞭,而且你也並不知道,項目中哪個組件有用到這個變量,有沒有在其他組件中進行改變,所以這個api在項目中很少人使用,但是很多人拿來寫組件用
在很多開發情況下,我們隻是想把組件A的數據傳給組件C,如果用props來進行組件通信的話,雖然可以實現,但是代碼可讀性上不強,且難維護。
所以這時候,我們的主角$attrs
和 $listeners
就出現瞭
$attrs
和 $listeners
的用法
在vue2.4中,為瞭解決該需求,引入瞭$attrs
和$listeners
, 新增瞭inheritAttrs
選項。 在版本2.4以前,默認情況下父作用域的不被認作props的屬性屬性百年孤獨,將會“回退”且作為普通的HTML特性應用在子組件的根元素上。如下列的例子
父組件的代碼:
<template> <div> <child-dom :foo="foo" :bar="bar"></child-dom> </div> </template> <script> import ChildDom from "../components/attrs/ChildDom.vue"; export default { components: { ChildDom, }, data() { return { foo: "foo", bar: "bar", }; }, }; </script>
子組件的代碼:
<template> <div> <p>foo:{{ foo }}</p> </div> </template> <script> export default { props: ["foo"], }; </script>
我們先看一下這樣寫的時候,控制臺打印出來的dom結構是這樣的:
在2.4中新增選項inheritAttrs
,inheritAttrs
的默認值為true, 將inheritAttrs
的值設為false, 這些默認的行為會禁止掉。但是通過實例屬性 $attrs
,可以將這些特性生效,且可以通過v-bind
綁定到子組件的非根元素上。
將子組件的代碼修改一下:
<template> <div> <p>foo:{{ foo }}</p> <p>attrs: {{ $attrs }}</p> <dom-child v-bind="$attrs"></dom-child> </div> </template> <script> import DomChild from "./DomChild.vue"; export default { props: ["foo"], inheritAttrs: false, components: { DomChild, }, }; </script>
然後在加一個孫組件
<template> <div> <p>bar:{{ bar }}</p> </div> </template> <script> export default { props: ["bar"], }; </script>
頁面顯示如下:
從上面的代碼,可以看出使用$attrs
,inheritAttrs
屬性能夠使用簡潔的代碼,將組件A的數據傳遞給 組件C,該場景的使用范圍還是挺廣的。
那我們現在來看看組件C怎麼傳值給組件A?
vue2.4版本新增瞭$listeners
屬性,我們在組件B上 綁定 v-on=”$listeners”
, 在組件A中,監聽組件C觸發的事件。就能把組件C發出的數據,傳遞給組件A。
修改一下父組件的代碼:
<template> <div> <child-dom :foo="foo" :bar="bar" @upFoo="update"></child-dom> </div> </template> <script> import ChildDom from "../components/attrs/ChildDom.vue"; export default { components: { ChildDom, }, data() { return { foo: "foo", bar: "bar", }; }, methods: { update(val) { this.foo = val; console.log("update success"); }, }, }; </script>
子組件代碼:
<template> <div> <p>foo:{{ foo }}</p> <p>attrs: {{ $attrs }}</p> <dom-child v-bind="$attrs" v-on="$listeners"></dom-child> </div> </template> <script> import DomChild from "./DomChild.vue"; export default { props: ["foo"], inheritAttrs: false, components: { DomChild, }, }; </script>
孫組件代碼:
<template> <div> <p>bar:{{ bar }}</p> <button @click="startUpFoo">我要更新foo</button> </div> </template> <script> export default { props: ["bar"], methods: { startUpFoo() { this.$emit("upFoo", "foooooooooooo"); console.log("startUpFoo"); }, }, }; </script>
運行結果:
現在我們應該清楚瞭$attrs
,$listerners
,inheritAttrs
的作用瞭吧
到此這篇關於vue $attrs和$listeners的使用與區別的文章就介紹到這瞭,更多相關vue $attrs $listeners內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- Vue祖孫組件如何實現傳值
- 超實用vue中組件間通信的6種方式(最新推薦)
- vue3中$attrs的變化與inheritAttrs的使用詳解
- 簡單聊聊vue2.x的$attrs和$listeners
- Vue組件之間四種通信方式詳解