日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

React DnD简明教程

發(fā)布時(shí)間:2025/1/21 编程问答 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 React DnD简明教程 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

React DnD簡(jiǎn)明教程

概述

React Dnd不同于其他的拖拽庫(kù),如果你以前沒(méi)有用過(guò)它可能會(huì)被嚇到。然而,一旦你了解了它設(shè)計(jì)的一些核心概念,它將變得有意義。我建議你在閱讀文檔其他部分之前,先閱讀這些核心概念。

這些核心概念和flux/redux架構(gòu)相似。這并不是巧合,因?yàn)镽eact DnD內(nèi)部就是用的Redux。

Backends(后端)

React DnD是基于HTML5的拖放API搭建的。基本原因是這個(gè)API能夠截取拖拽的dom節(jié)點(diǎn)作為一個(gè)拖拽預(yù)覽。它的便利性就在于你不必為拖拽時(shí)的鼠標(biāo)繪制樣式。這個(gè)API也是處理文件拖拽上傳的唯一方式。

不幸的是,HTML5拖拽API也有缺點(diǎn)。它不支持觸摸屏,并且它在IE上提供的可定制機(jī)會(huì)要少于其他瀏覽器。

這就是為什么React DnD把HTML5的拖拽支持作為一種可插拔的方式來(lái)實(shí)現(xiàn)。你不必用它。你可以自己做一個(gè)不同的實(shí)現(xiàn),基于觸摸事件,鼠標(biāo)事件,甚至完全不同的東西。一些可插拔的(拖拽接口)實(shí)現(xiàn)在React DnD被稱作“backends”。React DnD目前僅提供了HTML5 backends,但是以后可能會(huì)添加更多的實(shí)現(xiàn)。

Backends承擔(dān)的角色有點(diǎn)像React的事件合成系統(tǒng):他們都抽象了瀏覽器的事件和DOM事件實(shí)現(xiàn)的區(qū)別。雖然有相似點(diǎn),React DnD的backends卻并不依賴React或事件合成系統(tǒng)。在底層,backends做的事情就是把DOM事件轉(zhuǎn)換成React DnD可以處理的Redux actions。

Items and Types(項(xiàng)和類型)

像Flux(或Redux),React DnD用數(shù)據(jù)作為真實(shí)的處理源,而不是界面。當(dāng)你在屏幕上拖動(dòng)一些東西時(shí),我們不說(shuō)是一個(gè)組件或者一個(gè)DOM節(jié)點(diǎn)被拖動(dòng)了。事實(shí)上,我們說(shuō)是某個(gè)特定的type(類型)的item(項(xiàng))被拖動(dòng)了。

什么是item?Item就是一個(gè)純js對(duì)象,用以描述什么被拖動(dòng)了。舉個(gè)例子,在看板應(yīng)用中,當(dāng)你拖動(dòng)一個(gè)卡片,item看起來(lái)可能像{cardId:42}。在一個(gè)象棋游戲中,當(dāng)你撿起一個(gè)棋子,item看起來(lái)可能像{fromCell: 'C5', piece: 'queen'}。用純對(duì)象描述拖拽數(shù)據(jù),可以幫助你解耦組件和使組件間互無(wú)干擾。

什么是type?type是一個(gè)字符串(或一個(gè)symbol)在應(yīng)用中唯一標(biāo)識(shí)items的完整類型。在看板應(yīng)用中,可能有一個(gè)“card”類型代表可拖動(dòng)的卡片,同時(shí)有一個(gè)“l(fā)ist”類型用以表示由這些卡片組成的可拖動(dòng)的列表。在象棋應(yīng)用中,可能只有一個(gè)“piece”類型。

Types(類型)是有用的,隨著你應(yīng)用的增長(zhǎng),你可能想讓更多東西可拖動(dòng),但是你不一定想放置目標(biāo)突然接受新的items(項(xiàng))。Types能讓你指定哪些拖拽源和放置目標(biāo)可兼容。你可能會(huì)枚舉出所有的type常量,就像枚舉Redux的action types一樣。

Monitors(監(jiān)控器)

拖拽本身是有狀態(tài)的。要么拖動(dòng)操作正在進(jìn)行,或者沒(méi)有。要么有一個(gè)類型和一個(gè)項(xiàng),或者沒(méi)有。狀態(tài)一定存在于某處。

React DnD通過(guò)一些被稱作monitors的包裝了內(nèi)部狀態(tài)存儲(chǔ)的封裝器把這些狀態(tài)暴露給組件。這些封裝器讓你更新組件props來(lái)響應(yīng)拖拽狀態(tài)的改變。

每個(gè)組件都需要跟蹤拖放狀態(tài),你可以定義一個(gè)收集函數(shù)來(lái)獲取從監(jiān)控器返回的一些細(xì)節(jié)。React DnD負(fù)責(zé)及時(shí)調(diào)用收集函數(shù)將返回結(jié)果合并到你的組件props中。

比如說(shuō)你想在某個(gè)棋子被拖動(dòng)后高亮棋盤格子。為Cell組件定義的收集函數(shù)可能像這樣:

function collect(monitor) {return { highlighted:monitor.canDrop(),hovered: monitor.isOver() }; }

這個(gè)函數(shù)會(huì)指示React DnD傳遞最新的highlighted和hovered的值給所有的Cell組件實(shí)例的屬性。

Connectors (連接器)

如果backend掌控的是DOM事件,而組件用的是React(虛擬DOM)描述DOM,那么backend怎么知道哪些DOM節(jié)點(diǎn)應(yīng)該被監(jiān)聽(tīng)勒?通過(guò)輸入connectors。連接器讓你在render函數(shù)中分配一條預(yù)定規(guī)則(拖拽源,拖拽預(yù)覽,放置目標(biāo))給DOM節(jié)點(diǎn)。

事實(shí)上,connector作為第一個(gè)參數(shù)被傳遞給我們上面提到的收集函數(shù)。我們來(lái)看看怎樣用它指定一個(gè)放置目標(biāo):

function collect(connect, monitor){return{highlighted:monitor.canDrop(),hovered: monitor.isOver(), connectDropTarget: connect.dropTarget()}; }

在組件的render方法中,能同時(shí)獲得從監(jiān)控器放回的數(shù)據(jù),和從連接器返回的函數(shù)。

render(){const { highlighted, hovered, connectDropTarget } = this.props; return connectDropTarget(<div className={classSet({'Cell': true,'Cell--highlighted': highlighted, 'Cell--hovered': hovered })}> {this.props.children} </div>); }

connectDropTarget告訴React DnD組件的根節(jié)點(diǎn)是一個(gè)有效的放置目標(biāo),并且backend應(yīng)該掌控它的hover和drop事件。在內(nèi)部它通過(guò)你指定的React元素的引用回調(diào)來(lái)工作。這個(gè)函數(shù)通過(guò)連接器memoized后返回的,所以它不會(huì)中斷shouldComponentUpdate 的優(yōu)化。

Drag Sources and Drop Targets(拖拽源和放置目標(biāo))

截止目前我們已經(jīng)介紹了和DOM打交道的backends,代表項(xiàng)和類型的數(shù)據(jù),以及收集函數(shù),得益于監(jiān)控器和連接器,你能描述React DnD應(yīng)該將哪些props注入到組件中。

但是我們?nèi)绾闻渲媒M件來(lái)實(shí)際接受這些注入的props呢?我們?cè)鯓訄?zhí)行具有副作用的拖放事件呢?是時(shí)候來(lái)會(huì)會(huì)drag sources(拖拽源)和drop targets(放置目標(biāo))了,這是React DnD主要的抽象單位。它們才是真正把類型、項(xiàng)、副作用操作,和收集函數(shù)連接到你組件中的東西。

無(wú)論何時(shí)你想讓你的組件或者它的一部分可拖動(dòng),你都需要用拖拽源聲明來(lái)包裝這個(gè)組件。每個(gè)拖拽源都需要注冊(cè)一個(gè)特定的類型,并且必須實(shí)現(xiàn)一個(gè)通過(guò)組件props生成項(xiàng)的方法。它也可以選擇性的指定其他一些方法來(lái)處理拖放事件。拖放源聲明還允許你為給定組件指定收集函數(shù)。

放置目標(biāo)和拖拽源十分相似。唯一的區(qū)別在于一個(gè)放置目標(biāo)可以同時(shí)注冊(cè)幾個(gè)項(xiàng)類型,而不是提供一個(gè)項(xiàng),它能掌控自己的hover和drop事件。

Higher-Order Components and ES7 decorators (高階組件和ES7修飾器)

你怎么包裝你的組件?包裝糾結(jié)是什么意思?如果你以前沒(méi)有用過(guò)高階組件,先讀讀這篇文章,它詳細(xì)介紹了這個(gè)概念。

所謂高階組件就是一個(gè)函數(shù),獲取一個(gè)React組件類并返回另一個(gè)不同的組件類。

The wrapping component provided by the library renders your component in its render method and forwards the props to it, but also adds some useful behavior.(這句目前不知道怎么翻譯,只好原文引用了。)

在React DnD中,DragSource和DropTarget,以及其他的一些頂級(jí)的對(duì)外函數(shù),實(shí)際上都是高階組件。他們把拖放魔法帶入到你的組件里。

一個(gè)關(guān)于使用它們的警告就是他們需要兩個(gè)應(yīng)用函數(shù)。舉個(gè)例子,這里是如何用DragSource包裝YourComponent:

import { DragSource } from 'react-dnd'; class YourComponent { /* ... */ } export default DragSource(/* ... */)(YourComponent);

注意,在指定DragSource的參數(shù)的時(shí)候發(fā)生了第一次調(diào)用,然后再最后傳遞你的組件類的地方,發(fā)生了第二次調(diào)用。這被稱為函數(shù)柯里化,或者偏函數(shù)用法,并且有必要?jiǎng)?chuàng)造性的使用ES7的修飾符語(yǔ)法。

你不必使用這個(gè)語(yǔ)法,但是如果你喜歡,你就能用Babel轉(zhuǎn)換你的代碼,并且在.babelrc文件里設(shè)置{ "stage": 1 }。

即使你不打算用ES7,偏函數(shù)用法也是依然有益的,因?yàn)樗梢詭湍阍贓S5或ES6中用有合并功能的輔助工具如 _.flow,合并幾個(gè)DragSource 和 DropTarget 聲明。在ES7中,你只需堆疊使用這些修飾符就能達(dá)到同樣效果。

import { DragSource } from 'react-dnd';@DragSource(/* ... */) @DropTarget(/* ... */) export default class YourComponent {render() {const { connectDragSource, connectDropTarget } = this.propsreturn connectDragSource(connectDropTarget(/* ... */))} }

Putting It All Together (總結(jié))

下面是一個(gè)包裝現(xiàn)有Card組件作為拖拽源的例子。

import React from 'react'; import { DragSource } from 'react-dnd';// Drag sources and drop targets only interact // if they have the same string type. // You want to keep types in a separate file with // the rest of your app's constants. const Types = {CARD: 'card' };/*** Specifies the drag source contract.* Only `beginDrag` function is required.*/ const cardSource = {beginDrag(props) {// Return the data describing the dragged itemconst item = { id: props.id };return item;},endDrag(props, monitor, component) {if (!monitor.didDrop()) {return;}// When dropped on a compatible target, do somethingconst item = monitor.getItem();const dropResult = monitor.getDropResult();CardActions.moveCardToList(item.id, dropResult.listId);} };// Use the decorator syntax @DragSource(Types.CARD, cardSource, (connect, monitor) => ({// Call this function inside render()// to let React DnD handle the drag events:connectDragSource: connect.dragSource(),// You can ask the monitor about the current drag state:isDragging: monitor.isDragging() })) export default class Card {render() {// Your component receives its own props as usualconst { id } = this.props;// These two props are injected by React DnD,// as defined by your `collect` function above:const { isDragging, connectDragSource } = this.props;return connectDragSource(<div>I am a draggable card number {id}{isDragging && ' (and I am being dragged now)'}</div>);} }

現(xiàn)在你已經(jīng)掌握了足夠的信息去探索文檔余下的部分了。

這個(gè)實(shí)例將是一個(gè)不錯(cuò)的開(kāi)始。

參考鏈接:https://liunianmou.gitbooks.io/react-dnd/content/chapter1.html

總結(jié)

以上是生活随笔為你收集整理的React DnD简明教程的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。