最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

使用react-dnd編寫一個可拖拽排列的list

 更新時間:2024年03月15日 11:15:01   作者:利器之路  
這篇文章主要為大家詳細介紹了如何使用react-dnd編寫一個可拖拽排列的list,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學習一下

今天的需求來啦:做一個可以通過拖拽排列的list。最終效果是這樣:

開始之前,我找了個市面上比較主流的工具庫,做個比對:

react-beautiful-dnd

這個是atlassian用來開發(fā)jira看板功能的庫,有動畫效果,很漂亮,確實對得起這個包的名字。優(yōu)點是相對易用,而且好看,缺點是僅適合開發(fā)list一類的組件,而且?guī)啄昵熬鸵呀?jīng)不再維護了,對于新版的函數(shù)式react可能不太兼容。

  • dnd-kit這個是atlassian在棄用react-beautiful-dnd后重新維護的一個版本,效果是一樣的美麗,如果是web端的,還是很推薦的。
  • reat-dnd這是個比較全面的dnd庫,可以實現(xiàn)各種功能,要注意的是這是基于H5的開發(fā),如果你開發(fā)的端不是H5,可能不適用。

react-dnd的官方文檔介紹了如何做一個棋盤,類似的,這篇文章將介紹如何用react-dnd做一個draggable list。

Draggable

首先將list中的每一個item做成draggable組件。

引入useDrag

// ListItem.tsx
import { styled } from '@mui/material/styles';
import * as React from 'react';
import { useDrag } from 'react-dnd';

const StyledListItem = styled('div', {
  shouldForwardProp: prop => prop !== 'isDragging'
})<{ isDragging: boolean }>(({ isDragging, theme }) => ({
  opacity: isDragging ? 0.5 : 1,
  border: '1px blue solid',
}));

const ListItem = () => {
  const [{isDragging}, dragRef] = useDrag(() => ({
    type: 'listItem',
    collect: monitor => ({
      isDragging: !!monitor.isDragging(),
    }),
  }))

  return (
    <StyledListItem ref={dragRef} isDragging={isDragging}>
      list item
    </StyledListItem>
  )
}

export default ListItem;

這樣我們在demo中就能看到,這個組件就可以用鼠標拖了:

Droppable

我們再將list容器做成droppable組件,這樣draggable組件才可以放在droppable的list里。

引入useDrop

// SortableList.tsx
import React, { forwardRef } from 'react';
import { useDrop } from 'react-dnd';
import ListItem from './components/listItem';

const SortableList = () => {

  const canMoveItem = () => {
    console.log('canMoveItem')
    return true;    //<--- 具體邏輯后面再寫,這里先設為true,即容器內(nèi)部一直是可以drop的。
  }

  const moveItem = () => {
    console.log('moveItem');    //<--- 具體邏輯后面再寫。
  }

  const [{ isOver, canDrop }, dropRef] = useDrop(
    () => ({
      accept: 'listItem',
      canDrop: () => canMoveItem(),
      drop: () => moveItem(),
      collect: (monitor) => ({
        isOver: !!monitor.isOver(),
        canDrop: !!monitor.canDrop()
      })
    }),
    [canMoveItem, moveItem]
  )
  
  return (
    <div>
      isOver: {String(isOver)}<br />
      canDrop: {String(canDrop)}
      <div
        ref={dropRef}
        style={{
          position: 'relative',
          width: '600px',
          height: '400px',
          border: '2px purple solid'
        }}
      >
        <ListItem></ListItem>
      </div>
    </div>
  );
}

export default SortableList;

這樣頁面上,我再容器內(nèi)部拖動時,isOvertrue,canDroptrue,拖到容器外isOver就變成false了:

既是draggable,又是droppable

當有多個list item,可以通過拖拽調(diào)整順序,這樣我需要將list item也變成droppable

// ListItem.tsx
// 將list item也變成droppable
const [spec, dropRef] = useDrop({
    accept: 'listItem',
    hover: (item, monitor) => {
        const dragIndex = item.index
        const hoverIndex = index
        const hoverBoundingRect = ref.current?.getBoundingClientRect()
        const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2
        const hoverActualY = monitor.getClientOffset().y - hoverBoundingRect.top

        // 如果是向下拖,只有當hover的坐標小于自身高度的一半時,繼續(xù)保持drag,否則相當于要挪動其他的list item,給當前的item騰個地方
        // if dragging down, continue only when hover is smaller than middle Y
        if (dragIndex < hoverIndex && hoverActualY < hoverMiddleY) return
        // 如果是向上拖,只有當hover的坐標大于自身高度的一半時,繼續(xù)保持drag,否則相當于要挪動其他的list item,給當前的item騰個地方
        if (dragIndex > hoverIndex && hoverActualY > hoverMiddleY) return
        moveListItem(dragIndex, hoverIndex)
        item.index = hoverIndex
    },
});

那么如何讓一個list item既是draggable,又是droppable呢?用以下方式:

// ListItem.tsx
const ref = useRef(null);

const dragDropRef = dragRef(dropRef(ref))

重排list

上一步我們把moveListItem傳給了父組件,那么在父組件中,我們可以這樣來改變list的順序:

// Mock data
const PETS = [
  { id: 1, name: 'dog' },
  { id: 2, name: 'cat' },
  { id: 3, name: 'fish' },
  { id: 4, name: 'hamster' },
]
// SortableList.tsx
const moveListItem = useCallback(
    (dragIndex, hoverIndex) => {
        console.log({dragIndex, hoverIndex})
        const dragItem = pets[dragIndex]
        const hoverItem = pets[hoverIndex]
        // 將PETS數(shù)組中,drag的item和hover的item交換位置
        setPets(pets => {
            const updatedPets = [...pets]
            updatedPets[dragIndex] = hoverItem
            updatedPets[hoverIndex] = dragItem
            return updatedPets
        })
    },
    [pets],
)

這樣我們就能得到這樣的效果:

這樣一個sortable list就大功告成啦!

總結(jié)

現(xiàn)在這個list是沒有任何動畫的,要是listItem在移動的過程中是有個過渡效果的,就顯得絲滑多了,那么接下來我將用react-flip-move將動畫效果加到每個item中。

到此這篇關(guān)于使用react-dnd編寫一個可拖拽排列的list的文章就介紹到這了,更多相關(guān)react-dnd可拖拽排列的list內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 淺談react性能優(yōu)化的方法

    淺談react性能優(yōu)化的方法

    這篇文章主要介紹了淺談react性能優(yōu)化的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-09-09
  • React?split實現(xiàn)分割字符串的使用示例

    React?split實現(xiàn)分割字符串的使用示例

    當我們需要將一個字符串按照指定的分隔符進行分割成數(shù)組時,我們可以在組件的生命周期方法中使用split方法來實現(xiàn)這個功能,本文就來介紹一下,感興趣的可以了解下
    2023-10-10
  • React中重新實現(xiàn)強制實施表單的流程步驟

    React中重新實現(xiàn)強制實施表單的流程步驟

    這篇文章主要介紹了React中重新實現(xiàn)強制實施表單的流程步驟,就像設計人員一樣,在添加邏輯之前,您需要為不同的狀態(tài)“模擬”或創(chuàng)建“模擬”,例如,這里只是表單的視覺部分的模擬,文中通過代碼示例講解的非常詳細,需要的朋友可以參考下
    2024-05-05
  • React 組件的狀態(tài)下移和內(nèi)容提升的操作方法

    React 組件的狀態(tài)下移和內(nèi)容提升的操作方法

    這篇文章主要介紹了React 組件的狀態(tài)下移和內(nèi)容提升,通過代碼講解了渲染性能的組件問題結(jié)合實例代碼給大家講解的非常詳細,需要的朋友可以參考下
    2022-11-11
  • Redux Toolkit 實戰(zhàn)使用指南

    Redux Toolkit 實戰(zhàn)使用指南

    Redux Toolkit 是 Redux 官方推出的高效開發(fā)工具集,本文就來介紹一下Redux Toolkit 實戰(zhàn)使用指南,文中通過示例代碼介紹的非常詳細,需要的朋友們下面隨著小編來一起學習學習吧
    2026-03-03
  • React 首頁加載慢問題性能優(yōu)化案例詳解

    React 首頁加載慢問題性能優(yōu)化案例詳解

    這篇文章主要介紹了React 首頁加載慢問題性能優(yōu)化案例詳解,本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細內(nèi)容,需要的朋友可以參考下
    2021-09-09
  • React配置代理服務器的5種方法及使用場景

    React配置代理服務器的5種方法及使用場景

    這篇文章主要介紹了React配置代理服務器的5種方法,無論使用哪種方法,都需要確保代理服務器的地址和端口正確,并且在配置完成后重新啟動React開發(fā)服務器,使配置生效,需要的朋友可以參考下
    2023-08-08
  • react-router?v6實現(xiàn)權(quán)限管理+自動替換頁面標題的案例

    react-router?v6實現(xiàn)權(quán)限管理+自動替換頁面標題的案例

    這篇文章主要介紹了react-router?v6實現(xiàn)權(quán)限管理+自動替換頁面標題,這次項目是有三種權(quán)限,分別是用戶,商家以及管理員,這次寫的權(quán)限管理是高級權(quán)限能訪問低級權(quán)限的所有頁面,但是低級權(quán)限不能訪問高級權(quán)限的頁面,需要的朋友可以參考下
    2023-05-05
  • 使用react+redux實現(xiàn)計數(shù)器功能及遇到問題

    使用react+redux實現(xiàn)計數(shù)器功能及遇到問題

    使用redux管理數(shù)據(jù),由于Store獨立于組件,使得數(shù)據(jù)管理獨立于組件,解決了組件之間傳遞數(shù)據(jù)困難的問題,非常好用,今天重點給大家介紹使用react+redux實現(xiàn)計數(shù)器功能及遇到問題,感興趣的朋友參考下吧
    2021-06-06
  • 每天學習一個hooks?useMount

    每天學習一個hooks?useMount

    這篇文章主要為大家介紹了每天學習一個hooks?useMount,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-05-05

最新評論

定西市| 青河县| 卓尼县| 株洲市| 独山县| 江北区| 天峨县| 什邡市| 万山特区| 河南省| 嫩江县| 遂溪县| 福安市| 静安区| 新闻| 武清区| 华宁县| 泰来县| 泽普县| 双流县| 滦南县| 庆云县| 萨迦县| 广州市| 岫岩| 宁海县| 陆良县| 磴口县| 定安县| 霍州市| 无为县| 汉川市| 兴业县| 玉门市| 汾阳市| 栖霞市| 博湖县| 治多县| 全椒县| 孝感市| 奉新县|