Создайте вычисляемое свойство, зависящее от переменных в цикле жизненного цикла onMounted()

#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. Все в порядке. Вам нужно указать, какую функцию удалить из зарегистрированных прослушивателей событий.