欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

react-dnd?API拖拽工具詳細(xì)用法示例

 更新時間:2022年10月17日 16:30:07   作者:Jou24  
這篇文章主要為大家介紹了react-dnd?API拖拽工具的詳細(xì)用法示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

前言

最近公司準(zhǔn)備開發(fā)一個審批流系統(tǒng),其中會用到拖拽工具來搭建流程,關(guān)于拖拽的實(shí)現(xiàn)我們選擇了react-dnd這個庫,本文總結(jié)了react-dnd API的詳細(xì)用法,并附上不同場景的demo,希望對大家有用。

概念

React DnD 是一組 React 高階組件,使用的時候只需要使用對應(yīng)的 API 將目標(biāo)組件進(jìn)行包裹,即可實(shí)現(xiàn)拖動或接受拖動元素的功能。

在拖動的過程中,不需要開發(fā)者自己判斷拖動狀態(tài),只需要在傳入的 spec 對象中各個狀態(tài)屬性中做對應(yīng)處理即可,因?yàn)閞eact-dnd使用了redux管理自身內(nèi)部的狀態(tài)。

Some of these concepts resemble the Flux and Redux architectures.
This is not a coincidence, as React DnD uses Redux internally.

值得注意的是,react-dnd并不會改變頁面的視圖,它只會改變頁面元素的數(shù)據(jù)流向,因此它所提供的拖拽效果并不是很炫酷的,我們可能需要寫額外的視圖層來完成想要的效果,但是這種拖拽管理方式非常的通用,可以在任何場景下使用,非常適合用來定制。

核心API

介紹實(shí)現(xiàn)拖拽和數(shù)據(jù)流轉(zhuǎn)的核心API,這里以Hook為例。

DndProvider

如果想要使用 React DnD,首先需要在外層元素上加一個 DndProvider。

import { HTML5Backend } from 'react-dnd-html5-backend';
import { DndProvider } from 'react-dnd';
<DndProvider backend={HTML5Backend}>
    <TutorialApp />
</DndProvider>

DndProvider 的本質(zhì)是一個由 React.createContext 創(chuàng)建一個上下文的容器(組件),用于控制拖拽的行為,數(shù)據(jù)的共享,類似于react-redux的Provider。

Backend

上面我們給DndProvider傳的參數(shù)是一個backend,那么這里來解釋一下什么是backend

React DnD 將 DOM 事件相關(guān)的代碼獨(dú)立出來,將拖拽事件轉(zhuǎn)換為 React DnD 內(nèi)部的 redux action。由于拖拽發(fā)生在 H5 的時候是 ondrag,發(fā)生在移動設(shè)備的時候是由 touch 模擬,React DnD 將這部分單獨(dú)抽出來,方便后續(xù)的擴(kuò)展,這部分就叫做 Backend。它是 DnD 在 Dom 層的實(shí)現(xiàn)。

  • react-dnd-html5-backend : 用于控制html5事件的backend
  • react-dnd-touch-backend : 用于控制移動端touch事件的backend
  • react-dnd-test-backend : 用戶可以參考自定義backend

useDrag

讓DOM實(shí)現(xiàn)拖拽能力的構(gòu)子,官方用例如下

import { DragPreviewImage, useDrag } from 'react-dnd';
export const Knight: FC = () => {
    const [{ isDragging }, drag, preview] = useDrag(
        () => ({
            type: ItemTypes.KNIGHT,
            collect: (monitor) => ({
                isDragging: !!monitor.isDragging()
            })
        }),
        []
    );
    return (
        <>
            <DragPreviewImage connect={preview} src={knightImage} />
            <div
                ref={drag}
            >
                ?
            </div>
        </>
    );
};

useDrag返回三個參數(shù)

第一個返回值是一個對象 表示關(guān)聯(lián)在拖拽過程中的變量,需要在傳入useDrag的規(guī)范方法的collect屬性中進(jìn)行映射綁定,比如:isDraging,canDrag等

第二個返回值 代表拖拽元素的ref

第三個返回值 代表拖拽元素拖拽后實(shí)際操作到的dom

useDrag傳入兩個參數(shù)

  • 第一個參數(shù),是一個對象,是用于描述了drag的配置信息,常用屬性

type: 指定元素的類型,只有類型相同的元素才能進(jìn)行drop操作

item: 元素在拖拽過程中,描述該對象的數(shù)據(jù),如果指定的是一個方法,則方法會在開始拖拽時調(diào)用,并且需要返回一個對象來描述該元素。

end(item, monitor): 拖拽結(jié)束的回調(diào)函數(shù),item表示拖拽物的描述數(shù)據(jù),monitor表示一個 DragTargetMonitor 實(shí)例

isDragging(monitor):判斷元素是否在拖拽過程中,可以覆蓋Monitor對象中的isDragging方法,monitor表示一個 DragTargetMonitor 實(shí)例

isDragging: (monitor) => {
  return monitor.getItem() ? index === monitor.getItem().index : false;
},
collect: (monitor: any) => ({
    //當(dāng)傳入isDragging方法時,monitor.isDragging()方法指代傳入的方法
  isDragging: monitor.isDragging(),
}),

canDrag(monitor):判斷是否可以拖拽的方法,需要返回一個bool值,可以覆蓋Monitor對象中的canDrag方法,與isDragging同理,monitor表示一個 DragTargetMonitor 實(shí)例

collect:它應(yīng)該返回一個描述狀態(tài)的普通對象,然后返回以注入到組件中。它接收兩個參數(shù),一個 DragTargetMonitor 實(shí)例和拖拽元素描述信息item

  • 第二個參數(shù)是一個數(shù)組,表示對方法更新的約束,只有當(dāng)數(shù)組中的參數(shù)發(fā)生改變,才會重新生成方法,基于react的useMemo實(shí)現(xiàn)

DragSourceMonitor對象

DragSourceMonitor是傳遞給拖動源的收集函數(shù)的對象。它的方法允許您獲取有關(guān)特定拖動源的拖動狀態(tài)的信息。 常用的方法: canDrag():描述元素是否可以拖拽,返回一個bool值

isDragging():判斷元素是否在拖拽過程中,返回一個bool值

getItemType():獲取元素的類型,返回一個bool值

getItem():獲取元素的描述數(shù)據(jù),返回一個對象

getDropResult():拖拽結(jié)束,返回拖拽結(jié)果的構(gòu)子,可以拿到從drop元素中返回的數(shù)據(jù)

didDrop(): 拖拽結(jié)束,元素是否放置成功,返回一個bool值

getDifferenceFromInitialOffset(): 獲取相對于拖拽起始位置的相對偏移坐標(biāo)。

useDrop

實(shí)現(xiàn)拖拽物放置的鉤子,官方用例如下

function BoardSquare({ x, y, children }) {
  const black = (x + y) % 2 === 1
  const [{ isOver }, drop] = useDrop(() => ({
    accept: ItemTypes.KNIGHT,
    drop: () => moveKnight(x, y),
    collect: monitor => ({
      isOver: !!monitor.isOver(),
    }),
  }), [x, y])
  return (
    <div
      ref={drop}
      style={{
        position: 'relative',
        width: '100%',
        height: '100%',
      }}
    >
     ....
    </div>,
  )
}
export default BoardSquare

useDrag返回兩個參數(shù)

  • 第一個返回值是一個對象,表示關(guān)聯(lián)在拖拽過程中的變量,需要在傳入useDrop的規(guī)范方法的collect屬性中進(jìn)行映射綁定
  • 第二個返回值代表放置元素的ref

useDrop傳入一個參數(shù)

用于描述drop的配置信息,常用屬性

accept: 指定接收元素的類型,只有類型相同的元素才能進(jìn)行drop操作

drop(item, monitor): 有拖拽物放置到元素上觸發(fā)的回調(diào)方法,item表示拖拽物的描述數(shù)據(jù),monitor表示 DropTargetMonitor實(shí)例,該方法返回一個對象,對象的數(shù)據(jù)可以由拖拽物的monitor.getDropResult方法獲得

hover(item, monitor):當(dāng)拖住物在上方hover時觸發(fā),item表示拖拽物的描述數(shù)據(jù),monitor表示 DropTargetMonitor實(shí)例,返回一個bool值

canDrop(item, monitor):判斷拖拽物是否可以放置,item表示拖拽物的描述數(shù)據(jù),monitor表示 DropTargetMonitor實(shí)例,返回一個bool值

DropTargetMonitor對象

DropTargetMonitor是傳遞給拖放目標(biāo)的收集函數(shù)的對象。它的方法允許您獲取有關(guān)特定拖放目標(biāo)的拖動狀態(tài)的信息。 常用的方法:

canDrop():判斷拖拽物是否可以放置,返回一個bool值

isOver(options): 拖拽物掠過元素觸發(fā)的回調(diào)方法,options表示拖拽物的options信息

getItemType():獲取元素的類型,返回一個bool值

getItem():獲取元素的描述數(shù)據(jù),返回一個對象

didDrop(): 拖拽結(jié)束,元素是否放置成功,返回一個bool值

getDifferenceFromInitialOffset(): 獲取相對于拖拽起始位置的相對偏移坐標(biāo)。

數(shù)據(jù)流轉(zhuǎn)

看了API之后,實(shí)際上不能很好的認(rèn)識到每個狀態(tài)和每個方法的工作流程,所以,我這里畫了一張圖,幫助你更清晰的看到它的數(shù)據(jù)是如何流動的。

然后我們通過一個demo來更深刻的認(rèn)識這個過程

這里我們定義了幾個單詞,然后通過拖拽,將它放入對應(yīng)的分組里面

單詞代碼

const Word: FC = ({ type, text, id, ...props }: any) => {
  const [offsetX, setOffsetX] = useState(0);
  const [offsetY, setOffsetY] = useState(0);
  const [{ isDragging }, drag]: any = useDrag(() => ({
    type,
    item: { id, type },
    end(item, monitor) {
      let top = 0,
        left = 0;
      if (monitor.didDrop()) {
        const dropRes = monitor.getDropResult() as any;
        //獲取拖拽對象所處容器的數(shù)據(jù),獲取坐標(biāo)變化
        if (dropRes) {
          top = dropRes.top;
          left = dropRes.left;
        }
        //這里必須寫成函數(shù)的傳入方式,否則無法獲取上一個state
        setOffsetX((offsetX) => offsetX + left);
        setOffsetY((offsetY) => offsetY + top);
      } else {
        // 移出則回到原位
        setOffsetX(0);
        setOffsetY(0);
      }
    },
    collect: (monitor) => ({
      isDragging: !!monitor.isDragging(),
    }),
  }));
  return ...   // dom
  );
};

分組代碼

function Classification({ type, title }: any) {
  const [{ isOver, canDrop }, drop] = useDrop(
    () => ({
      accept: type,
      drop(_item: any, monitor: any) {
         // 獲取每一次放置相對于上一次的偏移量
        const delta = monitor.getDifferenceFromInitialOffset();
        const left = Math.round(delta.x);
        const top = Math.round(delta.y);
        // 回傳給drag
        return { top, left };
      },
      canDrop: (_item, monitor) => {
        const item = monitor.getItem() as any;
        return item.type === type;
      },
      collect: (monitor) => ({
        isOver: !!monitor.isOver(),
        canDrop: !!monitor.canDrop(),
      }),
    }),
    [],
  );
  return ...   // dom
  )

完整demo戳鏈接:github.com/AdolescentJ…

拖拽預(yù)覽

受限于瀏覽器API的控制,拖拽元素在開始拖拽之后,只能保持其本身的一個樣式,不能使用其他樣式預(yù)覽,針對此,react-dnd為我們提供了兩種解決方法。

DragPreviewImage

react-dnd提供的DragPreviewImage組件,讓我們在拖拽的時候,可以以圖片的形式預(yù)覽拖拽的元素

它接收兩個參數(shù),一個是useDrag返回的預(yù)覽ref,一個是需要預(yù)覽的圖片

使用

import { useDrag, DragPreviewImage } from 'react-dnd';
import apple from '../../assets/apple.png';
const DragPreviewImg = () => {
  const [{ isDragging }, drag, preview] = useDrag({
    type: 'DragDropBox',
    collect: (monitor) => ({
      isDragging: monitor.isDragging(),
    }),
  });
  return (
    <>
      <DragPreviewImage connect={preview} src={apple} />
      <div
        className='card_drag'
        ref={drag}
        style={{
          opacity: isDragging ? 0.5 : 1,
        }}
      >
        drag item prview an apple
      </div>
    </>
  );
};
export default DragPreviewImg;

效果

完整demo戳鏈接:github.com/AdolescentJ…

使用圖片來預(yù)覽拖拽元素確實(shí)可以解決一部分問題,但在實(shí)際場景中,拖拽的元素可能會很多,我們也不能找UI把所有類型的圖都給一張,并且很多比較復(fù)雜的dom圖片是不能取代的

所以要展示更加定制化的預(yù)覽樣式,我們可以使用下面這種。

useDragLayer

useDragLayer是一個鉤子,它允許你使用dom的方式自定義拖拽元

它的原理是,監(jiān)聽你的拖拽狀態(tài),在拖拽的時候,可以取到你拖拽狀態(tài)的數(shù)據(jù),并且它會創(chuàng)建一個你想預(yù)覽的dom,然后我們可以可以通過拖拽的狀態(tài)來改變它的樣式,達(dá)到取代預(yù)覽的效果。

使用

const CustomDragLayer = (props: any) => {
//monitor 是drag的 monitor
    const { itemType, isDragging, item, initialOffset, currentOffset } = useDragLayer((monitor) => ({
        item: monitor.getItem(),
        itemType: monitor.getItemType(),
        initialOffset: monitor.getInitialSourceClientOffset(),
        currentOffset: monitor.getSourceClientOffset(),
        isDragging: monitor.isDragging(),
      }));
      if (!isDragging) {
        return null;
      }
      return (
        <div style={layerStyles}>
            <div className='card_drag'>這里是預(yù)覽樣式</div>
        </div>
      );
}

預(yù)覽

完整demo戳鏈接:github.com/AdolescentJ…

其他使用場景

除了上面的例子,還有非常多的案例

批量拖拽

可以選擇多個元素進(jìn)行拖拽

拖拽排序

可以拖拽元素放置排序

完整demo戳鏈接:github.com/AdolescentJ…

最后

感謝你能看到這里,本文總結(jié)了react-dnd的API的使用以及常見的場景,希望對你有所幫助,后續(xù)會一直更新,當(dāng)然,如果可以的話不妨留一個贊再走呢。

參考鏈接

react-dnd.github.io/react-dnd/d…

http://www.dbjr.com.cn/article/265220.htm

以上就是react-dnd API拖拽工具詳細(xì)用法示例的詳細(xì)內(nèi)容,更多關(guān)于react-dnd API拖拽工具的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • React中常見的動畫實(shí)現(xiàn)的幾種方式

    React中常見的動畫實(shí)現(xiàn)的幾種方式

    本篇文章主要介紹了React中常見的動畫實(shí)現(xiàn)的幾種方式,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-01-01
  • React生命周期函數(shù)圖解介紹

    React生命周期函數(shù)圖解介紹

    生命周期函數(shù)指在某一時刻組件會自動調(diào)用并執(zhí)行的函數(shù)。React每個類組件都包含生命周期方法,以便于在運(yùn)行過程中特定的階段執(zhí)行這些方法
    2022-11-11
  • react實(shí)現(xiàn)原生下拉刷新

    react實(shí)現(xiàn)原生下拉刷新

    這篇文章主要為大家詳細(xì)介紹了react實(shí)現(xiàn)原生下拉刷新,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • React自定義hook的方法

    React自定義hook的方法

    Hook是 React 16.8 的新增特性。它通常與函數(shù)式組件同時使用??梢允购瘮?shù)式組件在不編寫 class 的情況下,可以擁有class組件的狀態(tài)、生命周期、引用等功能,這篇文章主要介紹了React自定義hook的相關(guān)知識,需要的朋友可以參考下
    2022-06-06
  • 詳解react如何實(shí)現(xiàn)復(fù)合組件

    詳解react如何實(shí)現(xiàn)復(fù)合組件

    在一些react項(xiàng)目開發(fā)中,常常會出現(xiàn)一些組合的情況出現(xiàn),這篇文章主要為大家介紹了復(fù)合組件的具體實(shí)現(xiàn),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-10-10
  • react使用echart繪制地圖的案例

    react使用echart繪制地圖的案例

    這篇文章主要介紹了react使用echart繪制地圖,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-01-01
  • react-diagram 序列化Json解讀案例分析

    react-diagram 序列化Json解讀案例分析

    今天帶來大家學(xué)習(xí)react-diagram 序列化Json解讀的相關(guān)知識,本文通過多種案例給大家分析序列化知識,通過圖文并茂的形式給大家介紹的非常詳細(xì),感興趣的朋友一起看看吧
    2021-05-05
  • 淺談react?16.8版本新特性以及對react開發(fā)的影響

    淺談react?16.8版本新特性以及對react開發(fā)的影響

    本文主要介紹了react?16.8版本新特性以及對react開發(fā)的影響,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • 關(guān)于React項(xiàng)目中的PDF展示解決方案

    關(guān)于React項(xiàng)目中的PDF展示解決方案

    這篇文章主要介紹了關(guān)于React項(xiàng)目中的PDF展示解決方案,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-07-07
  • 瀏覽器中視頻播放器實(shí)現(xiàn)的基本思路與代碼

    瀏覽器中視頻播放器實(shí)現(xiàn)的基本思路與代碼

    這篇文章主要給大家介紹了關(guān)于瀏覽器中視頻播放器實(shí)現(xiàn)的基本思路與代碼,并且詳細(xì)總結(jié)了瀏覽器中的音視頻知識,對大家的理解和學(xué)習(xí)非常有幫助,需要的朋友可以參考下
    2021-08-08

最新評論