关于前端:大家都能看得懂的源码-那些关于DOM的常见Hook封装二

4次阅读

共计 2803 个字符,预计需要花费 8 分钟才能阅读完成。

本文是深入浅出 ahooks 源码系列文章的第十五篇,该系列已整顿成文档 - 地址。感觉还不错,给个 star 反对一下哈,Thanks。

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

useFullscreen

治理 DOM 全屏的 Hook。

该 hook 次要是依赖 screenfull 这个 npm 包进行实现的。

抉择它的起因,预计有两个:

  • 它的兼容性好,兼容各个浏览器的全屏 API。
  • 简略,包体积小。压缩后只有 1.1 k。

大略介绍几个它的 API。

  • .request(element, options?)。使一个元素全屏显示。默认元素是 <html>
  • .exit()。退出全屏。
  • .toggle(element, options?)。如果目前是全屏,则退出,否则进入全屏。
  • .on(event, function)。增加一个监听器,用于当浏览器切换到全屏或切换出全屏或呈现谬误时。event 反对 ‘change’ 或者 ‘error’。另外两种写法:.onchange(function).onerror(function)
  • .isFullscreen。判断是否是全屏。
  • .isEnabled。判断以后环境是否反对全屏。

来看该 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 的可见性,即以后可见元素的上下文环境。由此能够晓得以后文档 (即为页面) 是在背地,或是不可见的暗藏的标签页,或者 (正在) 预渲染。可用的值如下:

  • ‘visible’ : 此时页面内容至多是局部可见. 即此页面在前景标签页中,并且窗口没有最小化。
  • ‘hidden’ : 此时页面对用户不可见。即文档处于背景标签页或者窗口处于最小化状态,或者操作系统正处于 ‘ 锁屏状态 ’。
  • ‘prerender’ : 页面此时正在渲染中,因而是不可见的。文档只能从此状态开始,永远不能从其余值变为此状态。

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

最初看这个 hook 的实现就很简略了:

  • 通过 document.visibilityState 判断是否可见。
  • 通过 visibilitychange 事件,更新后果。
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;
}

本文已收录到集体博客中,欢送关注~

正文完
 0