index.ts 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. import { watch, unref, Ref } from "../vue"
  2. // #ifdef APP-NVUE
  3. // const dom = weex.requireModule('dom')
  4. // const dom = uni.requireNativePlugin('dom')
  5. // #endif
  6. interface UseIntersectionObserverOptions {
  7. root ?: string; // 观察器的根元素选择器字符串
  8. rootMargin ?: {
  9. top ?: number; // 根元素顶部边距
  10. bottom ?: number; // 根元素底部边距
  11. left ?: number; // 根元素左侧边距
  12. right ?: number; // 根元素右侧边距
  13. }; // 根元素的边距
  14. thresholds ?: any[]; // 交叉比例数组,用于指定何时触发回调函数
  15. context ?: any; // 上下文对象,用于指定观察器的上下文
  16. initialRatio ?: number; // 初始的交叉比例
  17. observeAll ?: boolean; // 是否同时观察所有交叉对象
  18. }
  19. /**
  20. * 使用 Intersection Observer 观察元素可见性的自定义钩子函数
  21. * @param {Ref<string> | string} target - 目标元素,可以是一个字符串或 ref 对象
  22. * @param {(result: UniNamespace.ObserveResult) => void} callback - 回调函数,当目标元素的可见性发生变化时调用
  23. * @param {UseIntersectionObserverOptions} options - 可选的配置参数
  24. * @returns {Object} - 包含 stop 方法的对象,用于停止观察
  25. */
  26. export function useIntersectionObserver(
  27. target : Ref<string> | string,
  28. callback : (result : UniNamespace.ObserveResult) => void,
  29. options : UseIntersectionObserverOptions = {}) {
  30. const {
  31. root, // 观察器的根元素选择器
  32. rootMargin = { top: 0, bottom: 0 }, // 根元素的边距,默认为顶部和底部都为0
  33. thresholds = [0], // 交叉比例数组,默认为[0]
  34. initialRatio = 0, // 初始交叉比例,默认为0
  35. observeAll = false, // 是否同时观察所有交叉对象,默认为false
  36. context // 上下文对象,用于指定观察器的上下文
  37. } = options
  38. const noop = () => { }; // 空函数,用于初始化 cleanup
  39. let cleanup = noop; // 清理函数,用于停止 Intersection Observer 的观察
  40. const stopWatch = watch(() => ({ el: unref(target), root: unref(root) }), ({ el, root }) => {
  41. if (!el) {
  42. return
  43. }
  44. // #ifndef APP-NVUE
  45. // 创建 Intersection Observer 实例
  46. const observer = uni.createIntersectionObserver(context, { thresholds, initialRatio, observeAll })
  47. if (root) {
  48. // 相对于根元素设置边界
  49. observer.relativeTo(root, rootMargin)
  50. } else {
  51. // 相对于视口设置边界
  52. observer.relativeToViewport(rootMargin)
  53. }
  54. // 观察目标元素的可见性变化
  55. observer.observe(el, callback)
  56. cleanup = () => {
  57. // 停止观察
  58. observer.disconnect()
  59. // 将 cleanup 函数重置为空函数
  60. cleanup = noop
  61. }
  62. // #endif
  63. // #ifdef APP-NVUE
  64. // dom.getComponentRect(el, (res) => {
  65. // console.log('res', res)
  66. // })
  67. // #endif
  68. }, { immediate: true, flush: 'post' })
  69. const stop = () => {
  70. // 调用 cleanup 函数停止观察
  71. cleanup && cleanup()
  72. // 停止 watch
  73. stopWatch && stopWatch()
  74. }
  75. return { stop }
  76. }