简介

  • 能将任意列表转换为可拖动排序的 React 高阶组件,可将任何列表转换为动画,可访问和触摸友好的可排序列表 .

React 社区提供了许多的库来实现拖放的功能,例如 react-dnd, react-beautiful-dnd, react-drag-n-drop,等等。但是它们有一些共同的缺陷:

  • 使用复杂,有时候需要做很多工作才能构建一个简单的拖放演示;
  • 功能有限,例如无法实现多个拖放实例这样复杂的功能,

为了解决这些问题,react-sortable-hoc 应运而生。

React 官方推荐的封装高阶组件的方式是 HOC,我们需要借助它来实现一个具有拖放功能的高阶组件。

  • HOC 自身不是 React API 的一部分,它是一种基于 React 的组合特性而形成的设计模式。
  • HOC:higher Order Component,高阶组件。本质上是参数为组件,返回值为新组件的函数。

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import React, {Component} from 'react';
import {render} from 'react-dom';
import {SortableContainer, SortableElement} from 'react-sortable-hoc';
import arrayMove from 'array-move';

const SortableItem = SortableElement(({value}) => <li>{value}</li>);

const SortableList = SortableContainer(({items}) => {
return (
<ul>
{items.map((value, index) => (
<SortableItem key={`item-${index}`} index={index} value={value} />
))}
</ul>
);
});

class SortableComponent extends Component {
state = {
items: ['Item 1', 'Item 2', 'Item 3', 'Item 4', 'Item 5', 'Item 6'],
};
onSortEnd = ({oldIndex, newIndex}) => {
this.setState(({items}) => ({
items: arrayMove(items, oldIndex, newIndex),
}));
};
render() {
return <SortableList items={this.state.items} onSortEnd={this.onSortEnd} />;
}
}

render(<SortableComponent />, document.getElementById('root'));

例子2

准备拖拽的元素

1
2
3
4
5
6
7
8
9
10
11
12
// Gif.js
import React, { useState } from 'react';
import React from 'react';
import PropTypes from 'prop-types';

const Gif = ({ gif }) => (<img src={gif} alt="gif" />)

Gif.propTypes = {
gif: PropTypes.string.isRequired,
};

export default Gif;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// index.js
import React, { useState } from 'react';
import './App.css';

import Gif from './Gif';

const App = () => {
const [gifs, setGifs] = useState([
'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',
]);

return (
<div className="App">
<h1>Drag those GIFs around</h1>
<h2>Set 1</h2>
{gifs.map((gif, i) => <Gif key={gif} gif={gif} />)}
</div>
);
}

export default App;

添加拖放功能

现在让我们对 Gif 组件添加拖拽功能。

首先,我们需要了解 react-sortable-hoc 的两个 HOC,以及 array-move 的 arrayMove 方法,以便于在拖动发生修改数组。

  • sortableContainer 是所有可排序元素的容器;
  • sortableElement 是每个可渲染元素的容器。

首先引入对应组件以及方法

1
2
3
4
5
6
7
import { sortableContainer, sortableElement } from 'react-sortable-hoc';
import arrayMove from 'array-move';

// SortableGif 为每个子元素创建了一个容器,也就是为单个 Gif 组件创建。它们将使用在SortableGifsContainer 中,以 children 属性传递进去
const SortableGifsContainer = sortableContainer(({ children }) => <div className="gifs">{children}</div>);

const SortableGif = sortableElement(({ gif }) => <Gif key={gif} gif={gif} />);

然后用新创建的 SortableGif 替换原有的 Gif 组件,并在 SortableGifsContainer 中使用。

1
2
3
4
5
6
7
8
9
10
<SortableGifsContainer axis="x" onSortEnd={onSortEnd}>
{gifs.map((gif, i) =>
<SortableGif
// don't forget to pass index prop with item index
index={i}
key={gif}
gif={gif}
/>
)}
</SortableGifsContainer>