Vue 3 API композиции, не может вернуть значение из вспомогательной функции в компонент

я думаю, что это проблема области внутри моей вспомогательной функции, я успешно реализовал ту же логику в своем компоненте, и она работает отлично

я уже использовал составную функцию для использования ref() с переменной, которую я хочу вернуть

=> это рабочий код внутри моего компонента

// component.vue
setup() {
    const subnavDiv = ref(false) // this is the variable that the bellow code update

    onMounted(() => {
      const routEl = document.querySelector('.main')
      const fixedNav = document.querySelector('.main-nav')
      const el = document.querySelector('.search')

      let prevYPosition = 0
      let directionVar = 'up'
      const options = {
        root: routEl,
        rootMargin: `${fixedNav.offsetHeight * -1}px`,
        threshold: 0.7
      }

      const setScrollDirection = () => {
        if (routEl.scrollTop > prevYPosition) {
          directionVar = 'down'
        } else {
          directionVar = 'up'
        }
        prevYPosition = routEl.scrollTop
      }

      const onIntersection = ([e]) => {
        setScrollDirection()
        if ((directionVar === 'down' && e.boundingClientRect.top > 0) || !e.isIntersecting) {
          console.info('down')
          subnavDiv.value = true
        } else {
          subnavDiv.value = false
        }
        if (
          e.isIntersecting &&
          (e.boundingClientRect.top < fixedNav.offsetHeight ||
            e.boundingClientRect.top > fixedNav.offsetHeight)
        ) {
          subnavDiv.value = false
        }
      }

      const observer = new IntersectionObserver(onIntersection, options)
      observer.observe(el)
    })

    return {
      subnavDiv
    }
  }
}
}

=> после перемещения того же кода из компонента

// component.vue
setup() {
    const subnavDiv = ref(false)

    onMounted(() => {
      const rootEl = document.querySelector('.main')
      const fixedNav = document.querySelector('.main-nav')
      const el = document.querySelector('.search')

      subnavDiv.value = onIntersect(rootEl, 0.7, fixedNav, el) // the helper function call: this line is supposed to update the value of subnavDiv
    })
})


///////////////////////  $$$$$$$$$$$$$$$$$$  ///////////////

onIntersect.js // the helper function
const onIntersect = (rootElement, thresholdValue, elementToChange, elementToWatch) => {
  let prevYPosition = 0
  let directionVar = 'up'
  const options = {
    root: rootElement,
    rootMargin: `${elementToChange.offsetHeight * -1}px`,
    threshold: thresholdValue
  }
  let bool = false // this is the variable that i am trying to return from this function

  const setScrollDirection = () => {
    if (rootElement.scrollTop > prevYPosition) {
      directionVar = 'down'
    } else {
      directionVar = 'up'
    }
    prevYPosition = rootElement.scrollTop
  }

  const onIntersection = ([e]) => {
    setScrollDirection()
    if ((directionVar === 'down' && e.boundingClientRect.top > 0) || !e.isIntersecting) {
      console.info('down')
      bool = true
    } else {
      bool = false
    }
    if (
      e.isIntersecting &&
      (e.boundingClientRect.top < elementToChange.offsetHeight ||
        e.boundingClientRect.top > elementToChange.offsetHeight)
    ) {
      bool = false
    }
  }

  const observer = new IntersectionObserver(onIntersection, options)
  observer.observe(elementToWatch)

  return bool // the return (not returning any thing)
}

export default onIntersect
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
0
57
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Важной частью является ссылка. Целью шаблона ссылки является передача значения по ссылке между областями видимости. onIntersect должен быть составным и следовать обычным для них соглашениям. Его следует вызывать setup, а не хуки жизненного цикла.

Прямой доступ к DOM нежелателен в Vue. Если main и т. д. создаются в одних и тех же компонентах, они должны быть ссылками на шаблоны, в противном случае они могут быть предоставлены компонуемому объекту как ссылки, чтобы он мог использовать реактивность. Использование onMounted внутри составного объекта сделало бы его негибким и склонным к гонкам. Учитывая, что сначала необходимо получить доступ к elementToWatch, это может быть:

const useIntersect = (rootElRef, threshold, changedElRef, watchedElRef) => {
  const bool = ref(false);
  let observer;

  watchEffect(() => {
    const rootEl = unref(rootElRef);
    const changedEl = unref(changedElRef)
    const watchedEl = unref(watchedElRef);

    if (rootEl && watchedEl) {
      ...
      observer = new IntersectionObserver(onIntersection, options)
      observer.observe(watchedEl)
    }

    return () => {
      // clean up
      observer?.disconnect();
    }
  });

  return bool;
};

При необходимости к элементам DOM по-прежнему можно получить прямой доступ, но в любом случае они являются ссылками:

...
const rootElRef = ref(null);
const isSubnav = useIntersect(rootElRef, ...);
onMounted(() => {
  rootElRef.value = document.querySelector('.main');
  ...

В качестве побочного эффекта он может реагировать на изменения параметров, например. его можно принудительно воссоздать наблюдателя, если необходимо изменить параметры.

Благодарю за ваш ответ. но невозможно получить значения ссылок вне ловушки onMounted. поэтому ваши предложения не будут работать, и именно поэтому я использую вспомогательную функцию вместо составной функции, чтобы я мог вызывать ее внутри крючка onMounted

Ayoub Groubi 30.06.2024 12:46

Тогда это будет похоже на последний фрагмент шоу. Ваш случай не уникален, подобные проблемы постоянно решаются с помощью составных элементов.

Estus Flask 30.06.2024 12:49

в последнем фрагменте вы не можете получить доступ к обновленному значению ref внутри хука onMounted, поэтому вы не можете вызвать составную функцию вне хука onMounted. еще раз спасибо за ваш ответ

Ayoub Groubi 30.06.2024 13:24

Можете ли вы уточнить, что вы имеете в виду? rootElRef, ChangeElRef, WatchElRef содержат ссылки на элементы, которые недоступны в теле настройки, но доступны в смонтированном хуке, именно здесь вы назначаете значения, как только они становятся доступными. И наблюдатель не запустится, пока не будут доступны все элементы. Последний фрагмент должен заменять первый фрагмент в вопросе. Если по какой-то причине это у вас не работает, можете ли вы предоставить работоспособную демо-версию, чтобы ее можно было исправить?

Estus Flask 30.06.2024 13:33

это работоспособная демо: ссылка. все, что я хочу, это создать функцию многократного использования, чтобы я мог использовать ее повсюду в своем проекте. Спасибо

Ayoub Groubi 30.06.2024 16:43

Хорошо, спасибо. Именно так он и должен работать с минимальными изменениями имен и использования ссылок, codeandbox.io/p/sandbox/peaceful-goodall-4fxtgr. Если можно получить доступ к ссылкам на шаблоны «main» и т. д. напрямую вместо querySelector, как в этом примере, это будет лучший дизайн, но любой способ будет работать.

Estus Flask 30.06.2024 17:32

большое спасибо, но есть небольшая проблема; codeandbox говорит: «Вероятно, песочница, к которой вы пытаетесь получить доступ, не существует или у вас нет необходимых разрешений для доступа к ней». пожалуйста, проверьте разрешения, возможно, это не публично

Ayoub Groubi 30.06.2024 17:44

Я обновил, проверь

Estus Flask 30.06.2024 17:48

Я не знаю, как вас благодарить, все работает отлично, спасибо за поддержку

Ayoub Groubi 30.06.2024 18:29

Пожалуйста.

Estus Flask 30.06.2024 19:16

Другие вопросы по теме