那些关于DOM的常见Hook封装(二)

268次阅读  |  发布于2年以前

本文是深入浅出 ahooks 源码系列文章的第十五篇,这个系列的目标主要有以下几点:

本篇接着针对关于 DOM 的各个 Hook 封装进行解读。

useFullscreen

管理 DOM 全屏的 Hook。

该 hook 主要是依赖 screenfull[1] 这个 npm 包进行实现的。

选择它的原因,估计有两个:

大概介绍几个它的 API。

来看该 hook 的封装:

首先是 onChange 事件中,判断是否是全屏,从而触发进入全屏的函数或者退出全屏的函数。当退出全屏的时候,卸载 change 事件。

const { onExit, onEnter } = options || {};
// 退出全屏触发
const onExitRef = useLatest(onExit);
// 全屏触发
const onEnterRef = useLatest(onEnter);
const [state, setState] = useState(false);

const onChange = () => {
  if (screenfull.isEnabled) {
    const { isFullscreen } = screenfull;
    if (isFullscreen) {
      onEnterRef.current?.();
    } else {
      screenfull.off('change', onChange);
      onExitRef.current?.();
    }
    setState(isFullscreen);
  }
};

手动进入全屏函数,支持传入 ref 设置需要全屏的元素。并通过 screenfull.request 进行设置,并监听 change 事件。

// 进入全屏
const enterFullscreen = () => {
  const el = getTargetElement(target);
  if (!el) {
    return;
  }

  if (screenfull.isEnabled) {
    try {
      screenfull.request(el);
      screenfull.on('change', onChange);
    } catch (error) {
      console.error(error);
    }
  }
};

退出全屏方法,调用 screenfull.exit()

// 退出全屏
const exitFullscreen = () => {
  if (!state) {
    return;
  }
  if (screenfull.isEnabled) {
    screenfull.exit();
  }
};

最后通过 toggleFullscreen,根据当前状态,调用上面两个方法,达到切换全屏状态的效果。

// 切换模式
const toggleFullscreen = () => {
  if (state) {
    exitFullscreen();
  } else {
    enterFullscreen();
  }
};

useHover

监听 DOM 元素是否有鼠标悬停。

主要实现原理是监听 mouseenter 触发 onEnter 事件,切换状态为 true,监听 mouseleave 触发 onLeave 事件,切换状态为 false。代码简单,如下:

export default (target: BasicTarget, options?: Options): boolean => {
  const { onEnter, onLeave } = options || {};
  const [state, { setTrue, setFalse }] = useBoolean(false);
  // 通过监听 mouseenter 判断有鼠标悬停
  useEventListener(
    'mouseenter',
    () => {
      onEnter?.();
      setTrue();
    },
    {
      target,
    },
  );

  // mouseleave 没有鼠标悬停
  useEventListener(
    'mouseleave',
    () => {
      onLeave?.();
      setFalse();
    },
    {
      target,
    },
  );

  return state;
};

useDocumentVisibility

监听页面是否可见。

这个 hook 主要使用了 Document.visibilityState 这个 API。先简单看下这个 API:

Document.visibilityState (只读属性), 返回document的可见性, 即当前可见元素的上下文环境。由此可以知道当前文档 (即为页面) 是在背后, 或是不可见的隐藏的标签页,或者 (正在) 预渲染。可用的值如下:

典型用法是防止当页面正在渲染时加载资源,或者当页面在背景中或窗口最小化时禁止某些活动。

最后看这个 hook 的实现就很简单了:

const getVisibility = () => {
  if (!isBrowser) {
    return 'visible';
  }
  //  Document.visibilityState (只读属性), 返回document的可见性, 即当前可见元素的上下文环境。
  return document.visibilityState;
};

function useDocumentVisibility(): VisibilityState {
  const [documentVisibility, setDocumentVisibility] = useState(() => getVisibility());

  useEventListener(
    // 监听该事件
    'visibilitychange',
    () => {
      setDocumentVisibility(getVisibility());
    },
    {
      target: () => document,
    },
  );
  return documentVisibility;
}

参考资料

[1]screenfull: https://www.npmjs.com/package/screenfull

Copyright© 2013-2020

All Rights Reserved 京ICP备2023019179号-8