react实现拖拽容器边框改变容器宽度
- 先说下原理,显然拖拽容器触发事件然后改变容器宽度,这里因为无法获取到边框的拖拽事件,所以另辟蹊径使用div模拟一条容器的边框作为事件触发的触发器,并且需要获取同时获取左边、右边以及父容器的宽度在事件触发时重新计算容器宽度。
封装拖拽方法
const drag = ({ leftDom: ref1, rightDom: ref2, contentDom }, draggleLineDom) => {
const _ref1 = ref1;
const _ref2 = ref2;
draggleLineDom.onmousedown = e => {
let _e = e;
const dir = 'horizontal';
const firstX = _e.clientX;
const width = ref2.offsetWidth;
document.onmousemove = _event => {
_e = _event;
switch (dir) {
case 'horizontal':
let leftWidth = contentDom.offsetWidth - width + (_e.clientX - firstX) - 10;
let rightWidth = width - (_e.clientX - firstX);
if (leftWidth > 360 || leftWidth < 200) {
return;
}
_ref1.style.width = `${leftWidth}px`;
_ref2.style.width = `${rightWidth}px`;
break;
default:
break;
}
};
contentDom.onmouseup = () => {
document.onmousemove = null;
};
return false;
};
};
使用方法
import React, { useRef, useEffect } from 'react';
import Left from '../components/Left';
import Right from '../components/Right';
export default function Index() {
const draggleLineRef = useRef();
const contextRef = useRef();
const leftRef = useRef();
const rightRef = useRef();
useEffect(() => {
drag(
{ leftDom: leftRef.current, rightDom: rightRef.current, contentDom: contextRef.current },
draggleLineRef.current
);
}, []);
return (
<div style={{ height: '100%' }} ref={contextRef}>
<Left ref={leftRef} code={code} prefix="/statement/report" />
<div style={{ width: '3px', height: '100%', float: 'left', cursor: 'e-resize' }} ref={draggleLineRef}></div>
<Right ref={rightRef} code={code} />
</div>
);
}
table组件实现表头拖拽改变宽度
- 这里借助了react-resizable库来实现,借助render函数来实现拖拽功能。这里有几个问题,当设置初始width时,点击拖拽的同时会导致width瞬间的改变,显示会出问题,所以必须要将最后一列设置为充满的状态,因为无法在渲染时就获取到表头数量,也就无法获取每个表头均分的width,同时不要使用Table组件的自适应宽度
import React, { Component } from 'react';
import { Table, Pagination } from 'antd';
import { Resizable } from 'react-resizable';
import { withRouter } from 'react-router-dom';
const ResizeableTitle = props => {
const { onResize, width, ...restProps } = props;
if (!width) {
return <th {...restProps} />;
}
return (
<Resizable width={width} height={0} onResize={onResize}>
<th {...restProps} />
</Resizable>
);
};
class MyTable extends Component {
state = {
columns: this.props.columns
};
ref = React.createRef(null);
handleResize = index => (e, { size }) => {
this.setState(({ columns }) => {
const nextColumns = [...columns];
nextColumns[index] = {
...nextColumns[index],
width: size.width
};
return { columns: nextColumns };
});
};
componentDidMount() {
this.props.query();
this.unlisten = this.props.history.listen(route => {
if (route.pathname === '/report') {
this.props.query();
}
return;
});
}
componentWillUnmount() {
this.unlisten();
}
componentDidUpdate(props) {
if (this.props.columns !== props.columns) {
this.setState({ columns: this.props.columns });
}
}
components = {
header: {
cell: ResizeableTitle
}
};
render() {
const { rowKey, data, loading, isPagination, _props } = this.props;
const _columns = this.state.columns.map((col, index) => ({
...col,
width: col.width || 160,
onHeaderCell: column => ({
width: col?.width || 160,
onResize: this.handleResize(index)
})
}));
let scrollWidth = _.reduce(
_columns,
(width, item) => {
return width + item.width;
},
80
);
if (this.ref && this.ref.current && !_.isEmpty(_columns)) {
_columns[_columns.length - 1].onHeaderCell = null;
const { width } = this.ref.current.getBoundingClientRect();
if (scrollWidth < width) {
_columns[_columns.length - 1].width += width - scrollWidth;
scrollWidth = width;
}
}
const _pagination = {
current: this.props.pageNum,
pageSize: this.props.pageSize,
total: this.props.total
};
return (
<>
<div className="resizeable-table-wrapper" ref={this.ref}>
<Table
{..._props}
rowKey={rowKey}
loading={loading}
columns={_columns}
dataSource={data}
bordered
components={this.components}
pagination={isPagination ? _pagination : false}
/>
</div>
</>
);
}
}
MyTable.defaultProps = {
loading: false,
rowKey: 'id',
isPagination: true
};
export default withRouter(MyTable)