这篇文章基本骨架来自:文件点击上传和拖拽上传
今天我们要解决的问题就是页面上我们上传了多个文件,我们需要怎么实现移动拖拽排序的效果。
借用插件,先安装:
npm install --save react-sortable
参考官方文档:https://www.npmjs.com/package/react-sortable
实现效果:
思路:
- 要求每个图片必须是一个单独的组件
图片组件配置一共三步:
import React, { Component } from 'react'
// ①引包
import {sortable} from "react-sortable";
// ②装饰器语法进行组件装饰,注意这个装饰器就一个圆括号
// ③根 div 加上{...this.props}
@sortable
export default class Sortable extends Component {
render() {
return (
<div className = "cur" {...this.props}>
<img src = {this.props.base64}/>
</div>
)
}
}
如果不使用@这个语法糖就得这样写:
import React, { Component } from 'react'
// ①引包
import {sortable} from "react-sortable";
// ③根 div 加上{...this.props}
class Sortable extends Component {
render() {
return (
<div className = "cur" {...this.props}>
<img src = {this.props.base64}/>
</div>
)
}
}
// ②装饰器语法进行组件装饰,注意这个装饰器就一个圆括号
export default sortable(Sortable)
到这里拖拽图片的话基本就可看见拖拽效果,但是还不能看到排序的效果。
- 父组件也得三步操作,操作的地方就在子组件上
{
this.state.base64.map((item,index) => <Sortable key = {index} base64 = {item}
onSortItems={(arr)=>{
this.setState({
base64:arr
})
}}
items={this.state.base64}
sortId={index}
/>)
}
第一个地方:给子组件一个 sortId 一般 key 用啥就给它啥
第二个地方:items 给它的值就是当前进行 map 的数组
第三个地方:一个函数,很明显是使用排序好的数组来更新当前数组
没啦配置完成。
以下是 2019年08月29日的补充
二、react 拖拽的进化
上面的拖拽是非常的简单,特别像我以前使用原生 JS 模仿简书后台写的一个九宫格拖拽。这种有一个缺点,没有动画,在重视用户体验的情况下,这种插件是万万不能用的。其实实现动画原理也特别的简单,再源码在加个动画延迟就行了。今天在看 react-sortable npm 官网的时候,发现它推荐了两个动画特别流畅的 npm 包。react-sortable-hoc
和 react-beautiful-dnd
。随便选一个用一下,react-sortable-hoc
的下载量高一点就用它了。开始:
- 安装两个插件
npm install --save react-sortable-hoc
npm install --save array-move
先解释第二个:
array-move
就一个 API,它的主要作用就是用来交换数组中元素的位置。我们用 node 进行调试 1.js 文件,调试结果如下:
// 引包
const arrayMove = require('array-move');
// 创建一个数组
const input = ['a', 'b', 'c'];
// 以下三个排序实例
console.log(arrayMove(input, 1, 2));
//=> ['a', 'c', 'b']
console.log(arrayMove(input, -1, 0));
//=> ['c', 'a', 'b']
console.log(arrayMove(input, -2, -3));
//=> ['b', 'a', 'c']
node 1.js 运行文件,控制台输出结果如下:
C:\Users\Administrator\Desktop\my>node 1.js
[ 'a', 'c', 'b' ]
[ 'c', 'a', 'b' ]
[ 'b', 'a', 'c' ]
- 高阶函数
在熟练使用react-sortable-hoc
之前,先熟悉高阶函数。
高阶函数的定义简单来讲就是:高阶函数(Higher Order Function)=> 参数或返回值为函数
。
我们常见的有数组的遍历方式 Map、Reduce、Filter、Sort;常用的 redux 中的 connect 方法也是高阶函数。
这里在补充一个专有名词:函数的 柯里化
维基百科上:Currying(柯里化)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。
说白了就是一个函数调用的时候形参至少多余一个,柯里化就是在保证函数功能不变的情况下,把函数调用的形参限定只能是一个。
看一个简单加法器的案例:
//普通加法函数
function add(x,y){
return x + y;
}
add(8,9);
// 柯里化
function add(x){
// x这里属于闭包的概念
return function(y){
return x + y;
}
}
add(8)(9);
这玩意有啥用那,有函数不就行了?
可以提高函数的复用,例如一个字符串多次进行不同类型的正则查询。这个过程又有一个概念叫预处理。
请看演示:
// 正常正则验证字符串 reg.test(txt)
// 函数封装后
function check(reg, txt) {
return reg.test(txt)
}
check(/\d+/g, 'abc') //false
check(/[a-z]+/g, 'abc') //true
// 柯里化
function curryingCheck(txt) {
return function(reg) {
return reg.test(txt)
}
}
let has = curryingCheck("从我a1b2c3d4ef里面筛选只筛选出数字或字母!");
// 柯里化不像普通函数一样老是需要传入形参txt
has(/\d+/g); //true
has(/[a-z]/g)//true
react-sortable-hoc
使用
react-sortable-hoc
提供了两个特别重要的 API ,分别是SortableContainer 和 SortableElement
看英文的意思也知道,SortableElement
用来装饰每个要拖拽的组件,相对于SortableContainer
要装饰的组件,SortableElement
装饰的组件是子组件。SortableElement
提供了一个index
属性来进行子组件排序。SortableContainer
提供一个方法onSortEnd
。这个函数可以结构两个形参。{oldIndex, newIndex}
一个是拖拽元素的标记,一个是将要放的那个地方标记。最后在使用arrayMove
交换数组的位置。axis 是拖拽的方向,默认是 y ,垂直拖拽,x 表示只可以水平拖拽。
搞清楚这些上案例:
文件夹的逻辑结构就是 App.js 请求数据,数据是个数组传给子组件 B (用SortableContainer
装饰),孙子组件 A 来呈现图片(用SortableElement
装饰),另外本案例使用了语法糖@SortableContainer
完全可以替换为 SortableContainer(组件)
父组件:App.js
import React, { Component } from 'react';
import B from "./B";
import { SortableContainer } from 'react-sortable-hoc';
import arrayMove from 'array-move';
import axios from "axios";
export default class App extends Component {
constructor(){
super();
this.state = {
arr : [105,106,107]
}
}
render() {
this.onSortEnd = ({oldIndex, newIndex}) => {
this.setState({
arr: arrayMove(this.state.arr, oldIndex, newIndex)
});
};
return (
<div>
<B arr={this.state.arr} axis="x" onSortEnd={this.onSortEnd}/>
</div>
)
}
}
子组件 B.js
import React, { Component } from 'react';
import A from "./A";
import { SortableContainer } from 'react-sortable-hoc';
@SortableContainer
export default class B extends Component {
constructor(){
super();
}
render() {
return (
<div>
{this.props.arr.map((item,index)=><A collection="沙雕" key={item} item={item} index={index} onSortEnd={this.onSortEnd}/>)}
</div>
)
}
}
孙子组件A.js:
import React, { Component } from 'react';
import { sortableElement } from 'react-sortable-hoc';
@sortableElement
export default class A extends Component {
constructor(){
super();
}
render() {
return (
<div style={{"float":"left"}}>
{<img src={`./images/${this.props.item}.jpg`}/>}
</div>
)
}
}
运行效果: