這篇文章基本骨架來(lái)自:文件點(diǎn)擊上傳和拖拽上傳
今天我們要解決的問(wèn)題就是頁(yè)面上我們上傳了多個(gè)文件,我們需要怎么實(shí)現(xiàn)移動(dòng)拖拽排序的效果溺欧。
借用插件笔喉,先安裝:
npm install --save react-sortable
參考官方文檔:https://www.npmjs.com/package/react-sortable
實(shí)現(xiàn)效果:
思路:
- 要求每個(gè)圖片必須是一個(gè)單獨(dú)的組件
圖片組件配置一共三步:
import React, { Component } from 'react'
// ①引包
import {sortable} from "react-sortable";
// ②裝飾器語(yǔ)法進(jìn)行組件裝飾,注意這個(gè)裝飾器就一個(gè)圓括號(hào)
// ③根 div 加上{...this.props}
@sortable
export default class Sortable extends Component {
render() {
return (
<div className = "cur" {...this.props}>
<img src = {this.props.base64}/>
</div>
)
}
}
如果不使用@這個(gè)語(yǔ)法糖就得這樣寫(xiě):
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>
)
}
}
// ②裝飾器語(yǔ)法進(jìn)行組件裝飾糠惫,注意這個(gè)裝飾器就一個(gè)圓括號(hào)
export default sortable(Sortable)
到這里拖拽圖片的話(huà)基本就可看見(jiàn)拖拽效果实撒,但是還不能看到排序的效果遵蚜。
- 父組件也得三步操作,操作的地方就在子組件上
{
this.state.base64.map((item,index) => <Sortable key = {index} base64 = {item}
onSortItems={(arr)=>{
this.setState({
base64:arr
})
}}
items={this.state.base64}
sortId={index}
/>)
}
第一個(gè)地方:給子組件一個(gè) sortId 一般 key 用啥就給它啥
第二個(gè)地方:items 給它的值就是當(dāng)前進(jìn)行 map 的數(shù)組
第三個(gè)地方:一個(gè)函數(shù)奈惑,很明顯是使用排序好的數(shù)組來(lái)更新當(dāng)前數(shù)組
沒(méi)啦配置完成。
以下是 2019年08月29日的補(bǔ)充
二睡汹、react 拖拽的進(jìn)化
上面的拖拽是非常的簡(jiǎn)單肴甸,特別像我以前使用原生 JS 模仿簡(jiǎn)書(shū)后臺(tái)寫(xiě)的一個(gè)九宮格拖拽。這種有一個(gè)缺點(diǎn)囚巴,沒(méi)有動(dòng)畫(huà)原在,在重視用戶(hù)體驗(yàn)的情況下,這種插件是萬(wàn)萬(wàn)不能用的彤叉。其實(shí)實(shí)現(xiàn)動(dòng)畫(huà)原理也特別的簡(jiǎn)單庶柿,再源碼在加個(gè)動(dòng)畫(huà)延遲就行了。今天在看 react-sortable npm 官網(wǎng)的時(shí)候秽浇,發(fā)現(xiàn)它推薦了兩個(gè)動(dòng)畫(huà)特別流暢的 npm 包浮庐。react-sortable-hoc
和 react-beautiful-dnd
。隨便選一個(gè)用一下柬焕,react-sortable-hoc
的下載量高一點(diǎn)就用它了审残。開(kāi)始:
- 安裝兩個(gè)插件
npm install --save react-sortable-hoc
npm install --save array-move
先解釋第二個(gè):
array-move
就一個(gè) API,它的主要作用就是用來(lái)交換數(shù)組中元素的位置斑举。我們用 node 進(jìn)行調(diào)試 1.js 文件搅轿,調(diào)試結(jié)果如下:
// 引包
const arrayMove = require('array-move');
// 創(chuàng)建一個(gè)數(shù)組
const input = ['a', 'b', 'c'];
// 以下三個(gè)排序?qū)嵗?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 運(yùn)行文件,控制臺(tái)輸出結(jié)果如下:
C:\Users\Administrator\Desktop\my>node 1.js
[ 'a', 'c', 'b' ]
[ 'c', 'a', 'b' ]
[ 'b', 'a', 'c' ]
- 高階函數(shù)
在熟練使用react-sortable-hoc
之前富玷,先熟悉高階函數(shù)璧坟。
高階函數(shù)的定義簡(jiǎn)單來(lái)講就是:高階函數(shù)(Higher Order Function)=> 參數(shù)或返回值為函數(shù)
。
我們常見(jiàn)的有數(shù)組的遍歷方式 Map赎懦、Reduce雀鹃、Filter、Sort铲敛;常用的 redux 中的 connect 方法也是高階函數(shù)褐澎。
這里在補(bǔ)充一個(gè)專(zhuān)有名詞:函數(shù)的 柯里化
維基百科上:Currying(柯里化)是把接受多個(gè)參數(shù)的函數(shù)變換成接受一個(gè)單一參數(shù)(最初函數(shù)的第一個(gè)參數(shù))的函數(shù),并且返回接受余下的參數(shù)而且返回結(jié)果的新函數(shù)的技術(shù)伐蒋。
說(shuō)白了就是一個(gè)函數(shù)調(diào)用的時(shí)候形參至少多余一個(gè)工三,柯里化就是在保證函數(shù)功能不變的情況下迁酸,把函數(shù)調(diào)用的形參限定只能是一個(gè)。
看一個(gè)簡(jiǎn)單加法器的案例:
//普通加法函數(shù)
function add(x,y){
return x + y;
}
add(8,9);
// 柯里化
function add(x){
// x這里屬于閉包的概念
return function(y){
return x + y;
}
}
add(8)(9);
這玩意有啥用那俭正,有函數(shù)不就行了奸鬓?
可以提高函數(shù)的復(fù)用,例如一個(gè)字符串多次進(jìn)行不同類(lèi)型的正則查詢(xún)掸读。這個(gè)過(guò)程又有一個(gè)概念叫預(yù)處理串远。
請(qǐng)看演示:
// 正常正則驗(yàn)證字符串 reg.test(txt)
// 函數(shù)封裝后
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里面篩選只篩選出數(shù)字或字母!");
// 柯里化不像普通函數(shù)一樣老是需要傳入形參txt
has(/\d+/g); //true
has(/[a-z]/g)//true
react-sortable-hoc
使用
react-sortable-hoc
提供了兩個(gè)特別重要的 API 儿惫,分別是SortableContainer 和 SortableElement
看英文的意思也知道澡罚,SortableElement
用來(lái)裝飾每個(gè)要拖拽的組件,相對(duì)于SortableContainer
要裝飾的組件肾请,SortableElement
裝飾的組件是子組件留搔。SortableElement
提供了一個(gè)index
屬性來(lái)進(jìn)行子組件排序。SortableContainer
提供一個(gè)方法onSortEnd
铛铁。這個(gè)函數(shù)可以結(jié)構(gòu)兩個(gè)形參隔显。{oldIndex, newIndex}
一個(gè)是拖拽元素的標(biāo)記,一個(gè)是將要放的那個(gè)地方標(biāo)記饵逐。最后在使用arrayMove
交換數(shù)組的位置括眠。axis 是拖拽的方向,默認(rèn)是 y 倍权,垂直拖拽掷豺,x 表示只可以水平拖拽。
搞清楚這些上案例:
文件夾的邏輯結(jié)構(gòu)就是 App.js 請(qǐng)求數(shù)據(jù)薄声,數(shù)據(jù)是個(gè)數(shù)組傳給子組件 B (用SortableContainer
裝飾)萌业,孫子組件 A 來(lái)呈現(xiàn)圖片(用SortableElement
裝飾),另外本案例使用了語(yǔ)法糖@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>
)
}
}
運(yùn)行效果: