vue 3 组合 API,无法从辅助函数向组件返回值

问题描述 投票:0回答:1

我认为这是我的辅助函数内部的范围问题,我已经在我的组件中成功实现了相同的逻辑,并且它工作得很好

我已经使用可组合函数将 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.log('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.log('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
javascript vue.js vuejs3 vue-component intersection-observer
1个回答
0
投票

重要的部分是 ref,ref 模式的目的是在作用域之间通过引用传递值。

onIntersect
应该是可组合的,并遵循它们的常规约定。它应该在
setup
而不是生命周期钩子中调用。

在 Vue 中直接 DOM 访问是不可取的。如果在同一组件中创建

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 // the return (not returning any thing)
};

如有必要,仍然可以直接访问 DOM 元素,但无论如何它们都是引用:

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

作为副作用,它可以对参数的变化做出反应,例如如果需要更改选项,可以强制重新创建观察者。

© www.soinside.com 2019 - 2024. All rights reserved.