前言 - Prologue
嘗試寫 30 天文充實版面 (跳過假日 ლ(́◕◞౪◟◕‵ლ) ) 更新文章的 Day 26
在 Vue 中使用 computed
屬性和 $refs
來進行 DOM
操作是一個常見的需求,但是有時會遇到 computed
屬性中使用 $refs
時出現undefined
的問題。本文將介紹多種解決這個問題的方法使我們能夠順利地在 Vue 中使用 computed
和 $refs
進行 DOM
操作。
正文 - Main text
當在 Vue 的 computed
計算屬性中使用 $refs
進行 DOM
操作時,會出現 undefined
的問題,這是因為當 computed
屬性首次執行時, DOM
元素還尚未被渲染出來,所以 $refs
還不存在。
目前想到有五種方法,本篇將介紹其中三篇,其餘可在 Part2 找到。
- 在
watch
中監聽 $refs
是否變化
- 使用
$nextTick
延遲取得 $refs
computed
屬性加入 isMounted
變數
- 使用
$el
代替 $refs
屬性
- 在
mounted
中使用 setTimeout
延遲取得 $refs
方法一:在 watch
中監聽 $refs
是否變化
可以使用 Vue 的 watch
屬性,通過觀察 DOM
元素是否已經存在,然後進行相應的操作。
示例:
<template>
<div ref="myDiv">{{ myText }}</div>
</template>
<script>
export default {
data() {
return {
myText: "Hello, World!"
};
},
watch: {
"$refs.myDiv": {
handler(newVal) {
console.log("myDiv 已經存在:", newVal);
},
immediate: true
}
},
computed: {
myComputedText() {
return this.$refs.myDiv.innerText.toUpperCase();
}
}
};
</script>
上方使用了 watch
屬性來觀察 DOM
元素的存在。在 "$refs.myDiv"
的 handler
函數中進行了相應的 DOM
操作。同時在 watch
中使用了 immediate
選項,使得 handler
函數在初始化時就能夠執行。
immediate
是 Vue.js 中的一個 watch
選項,用於在監聽到資料變化後立刻執行 watch
的回調函數,而不是在下一次變化時執行。immediate
默認為 false
,若設置為 true
,則會在監聽時立刻執行回調函數。
在 computed
屬性中可以直接使用 $refs.myDiv
,是因為 watch
已經確保了其存在。
總之通過使用 Vue 的 watch
屬性可以避免在 computed
屬性中使用 $refs
時出現 undefined
的問題。
方法二:使用 $nextTick
延遲取得 $refs
通過 Vue 的 $nextTick
方法來解決在 computed
屬性中使用 $refs
時出現 undefined
的問題。
這個方法也是可行的,原理是在 DOM
渲染完成後再進行相應的 DOM
操作。
示例:
<template>
<div ref="myDiv">{{ myText }}</div>
</template>
<script>
export default {
data() {
return {
myText: "Hello, World!"
};
},
computed: {
myComputedText() {
this.$nextTick(() => {
console.log("myDiv 已經存在:", this.$refs.myDiv);
});
return this.$refs.myDiv.innerText.toUpperCase();
}
}
};
</script>
上方使用了 $nextTick
方法來確保 DOM
元素已經渲染完成。在 $nextTick
的回調函數中,可以進行相應的 DOM
操作。這樣在 computed
屬性中就可以直接使用 $refs.myDiv
,因為 $nextTick
方法已經確保了其存在。
總之使用 $nextTick
方法也是解決在 computed
屬性中使用 $refs
時出現 undefined
的問題的方法,它的原理是通過等待 DOM
渲染完成後再進行相應的 DOM
操作。
方法三:computed
屬性加入 isMounted
變數
通過引入 isMounted
變數,來解決在 computed
屬性中使用 $refs
時出現 undefined
的問題。
當 isMounted
為 true
時,computed
屬性中就可以正常使用 $refs
。
示例:
<template>
<div ref="myDiv">{{ myText }}</div>
</template>
<script>
export default {
data() {
return {
isMounted: false,
myText: "Hello, World!"
};
},
computed: {
myComputedText() {
if (!this.isMounted) return;
return this.$refs.myDiv.innerText.toUpperCase();
}
},
mounted() {
this.isMounted = true;
}
};
</script>
上面引入了一個 isMounted
變數,並在 computed
屬性中判斷其值,來解決在使用 $refs
時出現 undefined
的問題。在 mounted
生命週期中將 isMounted
設置為 true
,從而去允許 computed
屬性中使用 $refs
。
而需要注意的是,在 computed
屬性中返回一個常數時不會觸發資料的雙向綁定。因此若需要使用 computed
屬性來進行資料的雙向綁定,則需要返回一個可變的對象或陣列。
總之這種方法也是可行的,原理是通過引入一個 isMounted
變數來解決 computed
屬性中使用 $refs
時出現 undefined
的問題。
Other
除了上述的三種方法,應該還有一些可能的其他解决方法(?),像是下列兩種:
- 使用
$el
代替 $refs
屬性
- 在
mounted
中使用 setTimeout
延遲取得 $refs
參考資料 - Reference
[1] 解决 Vue computed 计算属性中使用 $refs 进行 dom 操作时出现 undefined 问题 _computed 使用 refs _ AwesomeDevin 的博客 - CSDN博客
https://blog.csdn.net/daivon_up/article/details/80149416
後記 - Epilogue
參考資料是當初的解決方法QQ,感謝各位分享知識的好心人ヽ(*・ω・)ノ!
明天有機會的話會繼續延續這個主體想一下還有沒有其他方法或是在 Vue3 該如何解決。
建置部落格時踩到的坑之一,紀錄一下 (o´∀`o)。
噹噹噹!續篇在這裡:
[Day 27] Vue computed 如何處理 $refs 中的 undefined 問題 Part2 - 嘗試 30 日寫文充版挑戰