组件文档 https://github.com/clauderic/react-sortable-hoc
在线demo https://clauderic.github.io/react-sortable-hoc/
npm install react-sortable-hoc --save
List拖拽
使用 distance prop设置触发排序之前要拖动的最小距离
- 例如设置10px的距离,distance={10}
- 这时直接点击就不会立即触发 SortableContainer上的点击事件
拖拽时可能会造成样式丢失,原因是你的样式可能存在父级
- 拖拽时 react-sorttable-hoc 会帮我们复制一份拖拽的dom节点,放到body下,
- 所以有父级样式就访问不到了。可以把样式直接写在body,注意class命名,别和其他冲突了
import React, { useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import { List, Switch, InputNumber } from 'antd';
import {
SortableContainer, SortableElement,
} from 'react-sortable-hoc';
import { arrayMove } from '@utils/array';
const itemStyle = { padding: '8px 15px', zIndex: 1000 };
const SortableItem = SortableElement(({ value }) => {
return (
<List.Item
style={itemStyle}
actions={[
<InputNumber
min={0}
max={100}
size='small'
defaultValue={value.sort}
/>,
<Switch checked={value.checked} />,
]}>
{value.title}
</List.Item>
);
});
const SortableList = SortableContainer(({ value }) => (
<List
dataSource={value}
renderItem={(item, index) =>
<SortableItem key={index} index={index} value={item} />}
/>
));
SortList.propTypes = {
value: PropTypes.array.isRequired,
onChange: PropTypes.func.isRequired,
};
function SortList({ value, onChange }) {
const [data, setList] = useState(value);
useEffect(() => {
setList(value);
}, [value]);
function onSortEnd({ oldIndex, newIndex }) {
if (oldIndex === newIndex) return;
const arr = arrayMove(data, oldIndex, newIndex);
setList(arr);
onChange(arr);
};
return (
<SortableList
value={data}
onSortEnd={onSortEnd}
distance={10}
/>
);
}
export default SortList;
九宫格拖拽
pressDelay设置低于300ms时,造成的问题:点击按钮click没有效果,解决:
- 在拖拽item项目里的class添加一个属性:
pointer-events: bounding-box
即可点击 - distance={10} 设置拖拽的最小距离
- https://github.com/clauderic/react-sortable-hoc/issues/206
pointer-events 阻止hover、active、onclick等触发事件来
https://www.imooc.com/article/48022
http://clauderic.github.io/react-sortable-hoc/#/basic-configuration/grid?_k=vq2z4r
Card卡片拖拽
https://css-tricks.com/draggin-and-droppin-in-react/
https://segmentfault.com/a/1190000020151524
card/index.js
import React, { useState } from 'react';
import styled from './index.module.less';
import {arrayMove} from '@utils/func'
import GifHoc from './GifHoc';
const array = [
'https://media.giphy.com/media/3ohhwoWSCtJzznXbuo/giphy.gif',
'https://media.giphy.com/media/l46CbZ7KWEhN1oci4/giphy.gif',
'https://media.giphy.com/media/3ohzgD1wRxpvpkDCSI/giphy.gif',
'https://media.giphy.com/media/xT1XGYy9NPhWRPp4pq/giphy.gif',
]
function Index() {
const [gifs, setGifs] = useState(array);
const [newGifs, setNewGifs] = useState([
'https://media.giphy.com/media/xiOgHgY2ceKhm46cAj/giphy.gif',
'https://media.giphy.com/media/3oKIPuMqYfRsyJTWfu/giphy.gif',
'https://media.giphy.com/media/4ZgLPakqTajjVFOVqw/giphy.gif',
'https://media.giphy.com/media/3o7btXIelzs8nBnznG/giphy.gif',
]);
// 每次拖动或排序项目时触发
function onSortEnd(item, e) {
const { oldIndex, newIndex, collection } = item;
console.log('onSortEnd', item, collection)
if(collection === 'gifs') {
return setGifs(arrayMove(gifs, oldIndex, newIndex));
}
setNewGifs(arrayMove(newGifs, oldIndex, newIndex));
}
return (
<div className={styled.card}>
<h1 className={styled.h1}>Drag those GIFs around</h1>
<h2 className={styled.h2}>Set 1</h2>
<GifHoc
dataSource={gifs}
collection="gifs"
onSortEnd={onSortEnd}
/>
<h2 className={styled.h2}>Set 2</h2>
<GifHoc
dataSource={newGifs}
collection="newGifs"
onSortEnd={onSortEnd}
/>
</div>
);
}
export default Index;
index.module.less
.card {
background: #1a1919;
color: #fff;
min-height: 100vh;
padding: 25px;
text-align: center;
.h1 {
font-size: 52px;
margin: 0;
}
.h2 {
color: #f6c945;
text-transform: uppercase;
}
.img {
cursor: grab;
height: 180px;
width: 240px;
}
}
SortableContainer
import React from 'react';
import PropTypes from 'prop-types';
import { sortableContainer, sortableElement } from 'react-sortable-hoc';
import styled from './index.module.less';
import Gif from './Gif'
// sortableContainer 所有可排序元素的容器
const SortableGifsContainer = sortableContainer(({ children }) => <div className="gifs">{children}</div>);
// sortableElement 每个拖拽元素的容器
const SortableGif = sortableElement(({ gif, index }) =>
<Gif gif={gif} key={index} />);
GifHoc.propTypes = {
dataSource: PropTypes.array.isRequired,
};
function GifHoc({ dataSource, collection, onSortEnd }) {
return (
<SortableGifsContainer
axis="x" // x 轴拖拽
onSortEnd={onSortEnd}
>
{dataSource.map((gif, i) =>
<SortableGif
// don't forget to pass index prop with item index
index={i}
key={gif}
gif={gif}
collection={collection} // 属于哪个集合
/>
)}
</SortableGifsContainer>
);
}
export default GifHoc;
SortableItem
import React from 'react';
import {string} from 'prop-types';
import styled from './index.module.less';
Gif.propTypes = {
gif: string.isRequired,
};
function Gif({ gif }) {
return (<img src={gif} alt="gif" className={styled.img}/>);
}
export default Gif;