先放下作者大大的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" />;
};
最近功力大漲,哭唧唧的,又可以欣賞許多有意思的項目啦啦啦啦啦啦啦
成爲牛逼的前端開發呀呀呀,發發發發發呀