使用hooks實現的react的一個拖動小demo
阿新 • • 發佈:2021-01-07
先放下作者大大的bolg地址:https://tinloof.com/blog/how-to-make-your-own-splitpane-react-component-with-0-dependencies/,
接下來我們來一起看看具體的效果和程式碼是如何實現的~~
我們看一下效果,其實就是一個可以拖動的效果,不過這個拖動的效果和我們常規的做法是不一樣的哦
這個是初始化的介面
這個是拖動後的介面
我們是明顯可以看到介面的變化,實現的特別之處在哪裡呢?我們一起看下程式碼。
index.tsx是入口檔案,這個地方在使用元件那裡也有特別之處哦
我們可以看到,包裹的元件那裡,是以物件的形式來引用元件的,我們來仔細看看,為什麼可以這樣使用呢~
在SplitPane.js中我們可以看到,我們是直接以函式物件的屬性的方法來定義的,在js中萬物皆物件,函式元件其實也是屬於物件,
函式元件同樣也可以是物件的屬性,我們定義的SplitPane函式元件,中間有用children進行佔位,故可以直接在App中引用其中
我們還需要注意的一段程式碼,我認為是這個demo中最精華的一句程式碼來
topRef.current.style.flex = "none";
為什麼這麼說呢?其實css在這裡有一個小技巧的。
我們可以看到初始化的時候,上面和下面兩部分的距離其實是相等的,都是flex:1,這個地方處理拖動的時候,是一旦存在移動的情況,
就直接將flex:none,是非常有技巧性,我們可以看到整個核心程式碼,行數不多,卻同樣可以實現功能
//SplitPane.js import React from "react"; const splitPaneContext = React.createContext(); export default function SplitPane({ children, ...props }) { const [topHeight, setTopHeight] = React.useState(null); const separatorYPosition = React.useRef(null); const splitPaneRef = React.createRef(); const onMouseDown = e => { separatorYPosition.current = e.clientY; }; const onMouseMove = e => { if (!separatorYPosition.current) { return; } const newTopHeight = topHeight + e.clientY - separatorYPosition.current; separatorYPosition.current = e.clientY; // if (newTopHeight <= 0) { // return topHeight !== 0 && setTopHeight(0); // } const splitPaneHeight = splitPaneRef.current.clientHeight; // if (newTopHeight >= splitPaneHeight) { // return topHeight !== splitPaneHeight && setTopHeight(splitPaneHeight); // } setTopHeight(newTopHeight); }; const onMouseUp = () => { separatorYPosition.current = null; }; React.useEffect(() => { document.addEventListener("mousemove", onMouseMove); document.addEventListener("mouseup", onMouseUp); return () => { document.removeEventListener("mousemove", onMouseMove); document.removeEventListener("mouseup", onMouseUp); }; }); return ( <div {...props} className="split-pane" ref={splitPaneRef}> <splitPaneContext.Provider value={{ topHeight, setTopHeight }}> {children[0]} <div className="separator" onMouseDown={onMouseDown} /> {children[1]} </splitPaneContext.Provider> </div> ); } SplitPane.Top = function SplitPaneTop(props) { const topRef = React.createRef(); const { topHeight, setTopHeight } = React.useContext(splitPaneContext); React.useEffect(() => { if (!topHeight) { setTopHeight(topRef.current.clientHeight); topRef.current.style.flex = "none"; return; } topRef.current.style.height = `${topHeight}px`; }, [topHeight]); return <div {...props} className="split-pane-top" ref={topRef} />; }; SplitPane.Bottom = function SplitPaneBottom(props) { return <div {...props} className="split-pane-bottom" />; };
最近功力大漲,哭唧唧的,又可以欣賞許多有意思的專案啦啦啦啦啦啦啦
成為牛逼的前端開發呀呀呀,發發發發發呀