從 Compat 2021 到 Interop 2022
Compat 2021 致力於消除瀏覽器相容性問題的五個主要焦點領域,使開發者可以在這些領域上自信地建立可靠的基礎。而 Interop 2022 的重點是在15個開發者認為在不同瀏覽器之間缺失或存在相容性問題時尤其困擾的領域上制定基準。2216 Words (12min read)

Photo by Emily Morter on Unsplash
嘗試寫 30 天文充實版面
(跳過假日 ლ(́◕◞౪◟◕‵ლ) )更新文章的 Day 27
接續上一篇貼文 [Day 26] Vue computed 如何處理 $refs 中的 undefined 問題 Part1 - 嘗試 30 日寫文充版挑戰 所述的其他可能的解決方法。
上一篇前言文案:
在 Vue 中使用 computed
屬性和 $refs
來進行 DOM
操作是一個常見的需求,但是有時會遇到 computed
屬性中使用 $refs
時出現undefined
的問題。本文將介紹多種解決這個問題的方法使我們能夠順利地在 Vue 中使用 computed
和 $refs
進行 DOM
操作。
當在 Vue 的 computed
計算屬性中使用 $refs
進行 DOM
操作時,會出現 undefined
的問題,這是因為當 computed
屬性首次執行時, DOM
元素還尚未被渲染出來,所以 $refs
還不存在。
目前想到有五種方法,本篇將介紹其中二篇,其餘可在 Part1 找到。
watch
中監聽 $refs
是否變化$nextTick
延遲取得 $refs
computed
屬性加入 isMounted
變數$el
代替 $refs
屬性mounted
中使用 setTimeout
延遲取得 $refs
$el
代替 $refs
屬性$el
屬性是 Vue 實例所掛載的元素,可以通過 this.$el
來取得。因為在 computed
屬性計算時,元素已經被掛載到 Vue 實例上了,所以使用 $el
可以避免未定義的問題。
computed: {
computedProp() {
// 使用 $el 替代 $refs
const el = this.$el.querySelector('.my-element')
return el ? el.offsetHeight : 0
}
}
示例1 - 使用計算屬性:
<template>
<div>
<div class="my-element">{{ myText }}</div>
</div>
</template>
<script>
export default {
data() {
return {
myText: "Hello, World!"
};
},
computed: {
myComputedText() {
const el = this.$el.querySelector(".my-element");
if (el) {
return this.myElement.innerText.toUpperCase();
} else {
return "";
}
}
}
};
</script>
上面例子在 myComputedText
計算屬性中使用了 this.$el
訪問了 Vue 實例的根 DOM
元素,然後使用 querySelector
方法選擇了 .my-element
元素。如果 .my-element
元素存在,我們就可以在 myComputedText
計算屬性中進行相應的 DOM
操作,例如:示例中將文字轉換為大寫。如果 .my-element
元素不存在,則返回一個空字符串。
注意:由於在模板中定義的
DOM
元素還沒有被完全掛載到 Vue 實例上,因此必須在computed
中訪問$el
屬性。
在computed
中進行DOM
操作有一定的風險,因為computed
是基於它所依賴的數據進行緩存的,如果沒有正確地管理依賴關係,可能會導致計算結果的不準確或無法更新。
建議使用$refs
屬性來操作DOM
元素,這樣可以更加安全和方便地訪問DOM
元素。
當使用 $el
屬性代替 $refs
屬性時,需要確保對應的 DOM
元素已經被掛載到 Vue 實例上。
示例2 - 使用方法屬性:
<template>
<div>
<button @click="handleClick">Click me</button>
<div class="my-element">{{ myText }}</div>
</div>
</template>
<script>
export default {
data() {
return {
myText: "Hello, World!"
};
},
methods: {
handleClick() {
const el = this.$el.querySelector(".my-element");
if (el) {
// 在這裡進行相應的 DOM 操作
el.style.color = "red";
}
}
}
};
</script>
上面例子通過 this.$el
訪問了 Vue 實例的根 DOM
元素,然後使用 querySelector
方法選擇了 .my-element
元素。如果 .my-element
元素存在,就可以在 handleClick
方法中進行相應的 DOM
操作,例如:將其文字顏色設置為紅色。
注意:由於在模板中定義的
DOM
元素還沒有被完全掛載到 Vue 實例上,因此必須在handleClick
方法中訪問$el
屬性。如果在mounted
鉤子中訪問$el
屬性,有可能無法訪問到.my-element
元素,因為它還沒有被完全掛載到 Vue 實例上。
mounted
中使用 setTimeout
延遲取得 $refs
mounted
是 Vue 實例掛載完成的生命週期鉤子,可以在這個階段取得 $refs
屬性,但為了確保取得 $refs
,需要使用 setTimeout
進行延遲。
mounted() {
setTimeout(() => {
const el = this.$refs.myElement
if (el) {
// 獲取到 $refs 後進行相應的操作
}
}, 0)
}
示例:
<template>
<div>
<div ref="myElement">{{ myText }}</div>
</div>
</template>
<script>
export default {
data() {
return {
myText: "Hello, World!"
};
},
mounted() {
// 在 mounted 階段,$refs.myElement 還不存在
console.log("$refs.myElement", this.$refs.myElement);
// undefined
// 使用 setTimeout 延遲一個微小的時間後,$refs.myElement 就可以正確地訪問
setTimeout(() => {
console.log("$refs.myElement", this.$refs.myElement);
// <div>Hello, World!</div>
}, 1);
},
computed: {
myComputedText() {
return this.$refs.myElement ? this.$refs.myElement.innerText.toUpperCase() : "";
}
}
};
</script>
上方例子在 mounted
鉤子使用 setTimeout
延遲了一個極短的時間,以確保 $refs.myElement
已經存在於 Vue 實例中。在 computed
屬性 myComputedText
中,如果 $refs.myElement
存在,則可以進行相應的 DOM
操作。
每種解決方法都有其適用的情況和限制。
例如:
$nextTick
可以確保 $refs
屬性所對應的 DOM
元素已經被渲染出來,但需要額外的程式碼來處理異步操作。mounted
鉤子函數中訪問 $refs
屬性可以簡單地解決問題,但需要等待整個 Vue 實例都被渲染出來之後才能訪問 $refs
屬性。watch
屬性可以監聽 $refs
的變化,但可能會造成不必要的計算開銷和性能損失。$el
屬性代替 $refs
屬性可以避免未定義的問題,但在 computed
中進行 DOM 操作有一定的風險。因此在使用這些解決方法時,需要根據具體情況斟酌使用哪一種解決方法,以達到最佳的效果,同時可以根據具體情況探索出更加適合的解決方法,以上都只是想到參考的解決方法,一定會有更佳的方法還沒探索出來。
[Day 27] Vue computed 如何處理 $refs 中的 undefined 問題 Part2 - 嘗試 30 日寫文充版挑戰
Author
Released
2216 Words (12min read)
2161 Words (11min read)
1851 Words (10min read)