useStartTyping
document注册keydown事件,检查事件触发时activeElement是不是input和textarea以及是不是有contenteditable属性,以及检查keyCode的值是不是在有效范围,排除ctl alt等等。
const isFocusedElementEditable = () => { const { activeElement, body } = document; if (!activeElement) { return false; } // If not element has focus, we assume it is not editable, too. if (activeElement === body) { return false; } // Assume <input> and <textarea> elements are editable. switch (activeElement.tagName) { case 'INPUT': case 'TEXTAREA': return true; } // Check if any other focused element id editable. return activeElement.hasAttribute('contenteditable'); }; const isTypedCharGood = ({ keyCode, metaKey, ctrlKey, altKey }: KeyboardEvent) => { if (metaKey || ctrlKey || altKey) { return false; } // 0...9 if (keyCode >= 48 && keyCode <= 57) { return true; } // a...z if (keyCode >= 65 && keyCode <= 90) { return true; } // All other keys. return false; }; const useStartTyping = (onStartTyping: (event: KeyboardEvent) => void) => { useLayoutEffect(() => { const keydown = event => { !isFocusedElementEditable() && isTypedCharGood(event) && onStartTyping(event); }; document.addEventListener('keydown', keydown); return () => { document.removeEventListener('keydown', keydown); }; }, []); }; 复制代码
useMeasure
- ResizeObserver 采用了 resize-observer-polyfill, 高阶组件react-virtualized-auto-sizer 也能做到类似功能监听功能
- 利用函数ref属性
- useState使用函数参数初始化ResizeObserver实例
const useMeasure = <T>(): [(instance: T) => void, ContentRect] => { const [rect, set] = useState({ width: 0, height: 0, top: 0, left: 0, bottom: 0, right: 0, }); const [observer] = useState( () => new ResizeObserver(entries => { const entry = entries[0]; if (entry) { set(entry.contentRect); } }) ); const ref = useCallback( node => { observer.disconnect(); if (node) { observer.observe(node); } }, [observer] ); return [ref, rect]; }; export default useMeasure; 复制代码
useClickAway
HTML Node的contains方法, 判断节点是否为该节点的后代节点。
const useClickAway = ( ref: RefObject<HTMLElement | null>, onClickAway: (event: KeyboardEvent) => void, events: string[] = defaultEvents ) => { const savedCallback = useRef(onClickAway); useEffect(() => { savedCallback.current = onClickAway; }, [onClickAway]); useEffect(() => { const handler = event => { const { current: el } = ref; el && !el.contains(event.target) && savedCallback.current(event); }; for (const eventName of events) { on(document, eventName, handler); } return () => { for (const eventName of events) { off(document, eventName, handler); } }; }, [events, ref]); }; 复制代码
useCss
借用了 CSS-in-JS library nano-css。
nano-css本身使用的是 CSSStyleSheet.insertRule
const useCss = (css: object): string => { const className = useMemo(() => 'react-use-css-' + (counter++).toString(36), []); const sheet = useMemo(() => new nano.VSheet(), []); useLayoutEffect(() => { const tree = {}; cssToTree(tree, css, '.' + className, ''); sheet.diff(tree); return () => { sheet.diff({}); }; }); return className; }; 复制代码
useDrop
监听document的dragover,dragenter,dragleave,dragexit,drop,paste等事件。
useDropArea
传入事件监听函数,返回bound各种方法以及是否hover属性。 boud方法需要挂载到节点,那么突破口就是bound。
通过bound注入事件,然后在事件里面拦截,再调用传入的监听函数。
看看调用
import {useDropArea} from 'react-use'; const Demo = () => { const [bond, state] = useDropArea({ onFiles: files => console.log('files', files), onUri: uri => console.log('uri', uri), onText: text => console.log('text', text), }); return ( <div {...bond}> Drop something here. </div> ); }; 复制代码
useFullscreen
引入了库 screenfull 。 基本就是request全屏然后,监听change事件。
当然对video进行了额外的处理。
const onWebkitEndFullscreen = () => { video!.current!.removeEventListener('webkitendfullscreen', onWebkitEndFullscreen); onClose(); }; const onChange = () => { if (screenfull) { const isScreenfullFullscreen = screenfull.isFullscreen; setIsFullscreen(isScreenfullFullscreen); if (!isScreenfullFullscreen) { onClose(); } } }; if (screenfull && screenfull.enabled) { try { screenfull.request(ref.current); setIsFullscreen(true); } catch (error) { onClose(error); setIsFullscreen(false); } screenfull.on('change', onChange); } else if (video && video.current && video.current.webkitEnterFullscreen) { video.current.webkitEnterFullscreen(); video.current.addEventListener('webkitendfullscreen', onWebkitEndFullscreen); setIsFullscreen(true); } else { onClose(); setIsFullscreen(false); } 复制代码
useSpeech
这个功能我以前不知道的说。
浏览器支持率居然将近 90%, Can i use |speechSynthesis
其实就用利用了window.speechSynthesis。 原生代码也就是
var utterance = new SpeechSynthesisUtterance('我们都是中国人'); window.speechSynthesis.speak(utterance) 复制代码
useWait
额,直接用的react-wait