#vue.js #vuejs3 #vue-composition-api
Вопрос:
У меня есть компонент, который должен вычислять некоторые значения с помощью DOM, и поэтому у меня есть onMounted()
крюк жизненного цикла. В onMounted()
я вычисляю некоторые значения (технически, это вычисляемые свойства), зависящие от элементов DOM.
Затем я использую значения, найденные в другом вычисляемом свойстве, leftOffset
. Мне нужно использовать leftOffset
in template
(это изменяет некоторые CSS, не совсем релевантные).
Ниже приведен мой setup()
:
setup() {
let showContent = ref(false);
let windowWidth = ref(null);
let contentHider = ref(null);
let contentHiderXPos ;
let contentHiderWidth ;
let leftWidth;
onMounted(() => {
// The DOM element will be assigned to the ref after initial render
windowWidth = ref(window.innerWidth);
contentHiderXPos = computed(() => contentHider.value.getBoundingClientRect().left);
contentHiderWidth = computed(() => contentHider.value.getBoundingClientRect().width);
leftWidth = computed(() => contentHiderXPos.value contentHiderWidth.value);
});
let leftOffset = computed(() => {
return -(windowWidth.value - leftWidth.value)
});
return {
contentHider,
leftOffset,
}
contentHider
ссылается на элемент DOM одного из дивов, определенных в template
.
Моя проблема, которая leftOffest.value
не определена , потому что она пытается получить доступ windowWidth.value
к и leftWidth.value
, которые также не определены. Я также пытался вставить leftOffset
внутрь onMounted()
, но тогда я не могу получить к нему доступ template
(он не определен).
Как я могу перестроить свой код таким образом, чтобы leftOffset
к нему можно было получить доступ как из template
, так и из значений, найденных в onMounted()
?
Я искал в Интернете, но не смог найти ничего конкретного для API композиции.
Ответ №1:
Ваше использование ref
неверно. Следуйте комментариям в приведенном ниже фрагменте.
Также это предполагает, что вы не хотите, чтобы window.innerwidth реагировал.
// dont create another ref => you are trying to assign a new object here, thus breaking the reactivity
// windowWidth = ref(window.innerWidth);
// do this instead
windowWidth.value = window.innerWidth
Если вы хотите innerWidth
, чтобы он был реактивным, вы должны использовать собственный прослушиватель событий, как это;
const windowWidth = ref(window.innerWidth)
onMounted(() => {
window.addEventListener('resize', () => {windowWidth.value = window.innerWidth} )
})
onUnmounted(() => {
window.removeEventListener('resize', () => {windowWidth.value = window.innerWidth})
})
Комментарии:
1. Если бы я создал
windowWidth
вычисляемое свойство, мне все равно нужно было бы добавлять прослушиватели событий в окно, чтобы сделатьinnerWidth
его реактивным?2. Да, свойства окна не являются реактивными в Vue
3. какой смысл удалять прослушиватель событий?
4. Потому что, если компонент будет перемонтирован, то будет зарегистрирован другой прослушиватель событий, и оба прослушивателя будут выполнены. Это неэффективно и также может быть подвержено ошибкам.
5. Все в порядке. Вам нужно указать, какую функцию удалить из зарегистрированных прослушивателей событий.