Vue中的ref可以用來給元素或子組件注冊引用信息,而$refs可以用來獲取ref注冊過的元素或組件,關於這一點概念,其實很容易理解,使用一下就可以上手了,詳細的概念參見 [vue-ref] [vue-$refs]
但是在實際項目中,會發現,有時候通過 this.$refs.ref名稱 來獲取對應的DOM或組件時,並不能成功,而要在后面加一個 [0] 才能成功獲取到。多留心一下,會發現好像是涉及到循環時,就會出現這種情況,那不如來多做幾組測試來驗證一下,順便試試各種特殊情況下的特別之處。
part 1 常規用法
當ref用在組件上時,通過$refs獲取的是該組件的實例,可進而調用組件內定義的方法、屬性等;
如下圖所示,當ref定義在組件Home上時,通過this.$refs.test獲取的是Home組件對應的實例對象,通常我們可以通過這種方式來調用某個組件內的methods、data中定義的數據、或是進而獲取其子組件等。
<template> <div id="app"> <Home ref="test" /> </div> </template> <script> import Home from './views/Home' export default { components: { Home }, mounted () { console.log(this.$refs.test) } } </script>
當ref用在DOM節點上時,通過$refs獲取的是該DOM元素節點。
如下圖所示,當ref定義在DOM元素上時,通過this.$refs.test獲取的是該DOM元素,且包含子元素,進而可以進行下一步的DOM操作。
<template> <div id="app"> <p ref="test"> <span>123</span> </p> </div> </template> <script> export default { mounted () { console.log(this.$refs.test) } } </script>
Part 2 多處ref引用的值相同時(非v-for內使用時)
當html中ref值相同的節點是兄弟節點時,通過$refs獲取到的是文檔中順序靠下的節點(使用在DOM上和組件上原則一致,以DOM為例)
<template> <div id="app"> <p ref="test"> <span>123</span> </p> <span ref="test">456</span> </div> </template> <script> export default { mounted () { console.log(this.$refs.test) } } </script>
當html中ref值相同的節點是嵌套關系時,比如父子關系,則通過$refs獲取到的是外層節點(使用在DOM上和組件上原則一致,以DOM為例)
<template> <div id="app"> <p ref="test"> <span ref="test">123</span> </p> </div> </template> <script> export default { mounted () { console.log(this.$refs.test) } } </script>
當html中ref值相同的節點不在同一層級,也不是嵌套關系時,仍然遵循文檔中順序靠下的節點被獲取的原則(使用在DOM上和組件上原則一致,以DOM為例)
<template> <div id="app"> <p ref="test">456</p> <p> <span ref="test">123</span> </p> </div> </template> <script> export default { mounted () { console.log(this.$refs.test) } } </script>
Part 3 當ref值是個變量時(非v-for內使用時)
ref值使用變量時,通過this.$refs[變量名稱]指向的依舊是該DOM節點或組件實例,不需要加[0],且當出現ref值重復時,仍然滿足Part2實踐中的原則
<template> <div id="app"> <p :ref="name"> <span>123</span> </p> </div> </template> <script> export default { data () { return { name: 'test' } }, mounted () { console.log(this.$refs[this.name]) } } </script>
Part 4 ref用在v-for上時
當ref值相同時,this.$refs[ref名稱]獲取到的是該DOM節點或組件的數組,此處以組件為例
<template> <div id="app"> <Home v-for="num in loop" :key="num" ref="test"></Home> </div> </template> <script> import Home from './views/Home' export default { components: { Home }, data () { return { loop: 3 } }, mounted () { console.log(this.$refs.test) } } </script>
當ref值不同時,this.$refs[ref名稱]無法獲取對應的DOM節點或是組件,需要在其后追加[0]才可訪問,此處以組件為例
<template> <div id="app"> <Home v-for="num in loop" :key="num" :ref="'test' + num"></Home> </div> </template> <script> import Home from './views/Home' export default { components: { Home }, data () { return { loop: 3 } }, mounted () { console.log(this.$refs.test1) } } </script>
總結:
1. ref用在DOM上時,通過this.$refs[ref名稱]訪問的是該DOM元素節點;ref用在組件上時,通過this.$refs[ref名稱]訪問的是該組件的實例對象,可以進而調用組件的方法或者獲取組件的屬性等;
2. 當同一組件內部,有多處ref引用值相同的情況時,this.$refs[ref名稱]指向文檔流中靠下的組件或DOM節點,若是父子關系,則指向父級組件或DOM節點;
3. 若ref的值是個變量,只要不是用在v-for里,通過this.$refs[變量名稱]指向的依舊是該DOM節點或組件實例,且當出現ref值重復時,仍然滿足取靠下的節點或是父級節點的規則;
4. 若ref用在v-for里,當循環內的ref值相同時,this.$refs[ref名稱]獲取到的是該DOM節點或組件的數組,當ref值不同時,需提供this.$refs[ref名稱][0]來獲取該DOM節點或組件實例。
以上各項實踐可能考慮的情況不一定全,若是有遇到其他情況出現不一樣的用法和結果,再進行補充。