簡單的可拖拽的react組件, 不依賴任何第三方的庫 項目地址css
npm/cnpm i simple-react-draggablereact
Attribute | Description | Type | Accepted Values | Default |
---|---|---|---|---|
list | data | Array | [{id,name}] | [] |
option | config | {} | ||
className | container style | css string | any | |
itemClassName | each item style | css string | any | |
onMove | listener | function | callback |
import Draggable from 'simple-react-draggable';
const list = [{
id: 1,
name: '測試1'
},{
id: 2,
name: '測試2'
},{
id: 3,
name: '測試3'
},{
id: 4,
name: '測試4'
},{
id: 5,
name: '測試6'
},{
id: 7,
name: '測試7'
}];
<Draggable list={list}/> 複製代碼
配置:git
option: (可選)github
const defaultOption = {
width: 50,
height: 20,
offsetX: 3,
offsetY: 3
};
複製代碼
itemClassName: (可選)npm
.draggable-item {
background: #f3f3f3;
border-radius: 4px;
overflow: hidden;
cursor: default;
font-size: 12px;
color: rgba(0,0,0,0.65);
text-align: center;
}
複製代碼
className: (可選)antd
.wrapper {
background: #fff;
border-radius: 4px;
border: 1px solid #d9d9d9;
box-sizing: border-box;
padding: 0;
margin: 0;
}
複製代碼
list: 須要排序的數據app
onMove: 把移動後的數據返回測試
type: callbackui
return: [{id, name}]this
總的思路: 找到要移動的數據的index和目標位置的元素的index, but how?
list.forEach((item,index) => {
items.push(
<div key={item.id} onDragStart = {(event) => this.onDragStart(event, index)} draggable style={{marginTop: offsetY, marginLeft: offsetX, width, height, lineHeight: height+'px'}} className={itemCls} > {item.name} </div>
);
})
// onDragStart 記錄index
event.dataTransfer.setData("position", position);
複製代碼
onDrop = (event) => {
let {list} = this.state,
position = event.dataTransfer.getData("position"),
targetIndex = this.calculateTargetIndex(event.target),
removeItem;
let {onMove} = this.props;
if(targetIndex !== -1){
removeItem = list.splice(position, 1)[0];
list.splice(targetIndex, 0, removeItem);
this.setState({list});
onMove && onMove(list)
}
}
複製代碼
1).計算拖拽容器的x,y,以及每一行能顯示多少移動元素
calculateDragContainer(){
let { option: {offsetX, width} } = this.state;
let c = ReactDOM.findDOMNode(this.refs.draggableContainer).getBoundingClientRect(),
col = parseInt((c.width - offsetX) / (width + offsetX));
return {
x: c.x,
y: c.y,
col
}
}
複製代碼
2). 計算item元素的x,y
calculateDragItem(target){
var t = ReactDOM.findDOMNode(target).getBoundingClientRect();
return {x: t.x, y: t.y}
}
複製代碼
3). 計算每個list中的i數據的行列值
calculateIndexRowCol(i, maxCol) { // index row col
let row, col;
row = Math.ceil(i / maxCol);
col = i % maxCol;
if(col === 0) {
col = maxCol;
}
return {row, col};
}
複製代碼
4). 計算目標位置的list元素的index
calculateTargetIndex(target){// 獲取目標元素的index
let { list, option: {width, height, offsetX, offsetY} } = this.state,
c = this.calculateDragContainer(),
t = this.calculateDragItem(target),
targetIndex = -1,targetX,targetY, i,
len = list.length;
if(t.x !== c.x && list.length > 0){ // 鼠標落在目標item上
for(i = 1; i <= len; ++i){
let {row, col} = this.calculateIndexRowCol(i, c.col);
targetX = ((col - 1) * width + col * offsetX) + c.x;
targetY = ((row - 1) * height + row * offsetY) + c.y;
if(targetX === t.x && targetY === t.y){
targetIndex = i - 1;
break;
}
}
}
return targetIndex;
}
複製代碼