先放下作者大大的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" />;
};
最近功力大涨,哭唧唧的,又可以欣赏许多有意思的项目啦啦啦啦啦啦啦
成为牛逼的前端开发呀呀呀,发发发发发呀