react-beautiful-dnd(3)交互demo测试

428 阅读3分钟

1.动态数量的列表(带有功能组件)和删除项目的能力

    import React, { useState } from 'react';
    import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd';

    // fake data generator
    const getItems = (count, offset = 0) =>
      Array.from({ length: count }, (v, k) => k).map((k) => ({
        id: `item-${k + offset}-${new Date().getTime()}`,
        content: `item ${k + offset}`,
      }));

    const reorder = (list, startIndex, endIndex) => {
      const result = Array.from(list);
      const [removed] = result.splice(startIndex, 1);
      result.splice(endIndex, 0, removed);

      return result;
    };

    /**
     * Moves an item from one list to another list.
     */
    const move = (source, destination, droppableSource, droppableDestination) => {
      const sourceClone = Array.from(source);
      const destClone = Array.from(destination);
      const [removed] = sourceClone.splice(droppableSource.index, 1);

      destClone.splice(droppableDestination.index, 0, removed);

      const result = {};
      result[droppableSource.droppableId] = sourceClone;
      result[droppableDestination.droppableId] = destClone;

      return result;
    };
    const grid = 8;

    const getItemStyle = (isDragging, draggableStyle) => ({
      // some basic styles to make the items look a bit nicer
      userSelect: 'none',
      padding: grid * 2,
      margin: `0 0 ${grid}px 0`,

      // change background colour if dragging
      background: isDragging ? 'lightgreen' : 'grey',

      // styles we need to apply on draggables
      ...draggableStyle,
    });
    const getListStyle = (isDraggingOver) => ({
      background: isDraggingOver ? 'lightblue' : 'lightgrey',
      padding: grid,
      width: 250,
    });

    function DynamicDrag() {
      const [state, setState] = useState([getItems(10), getItems(5, 10)]);

      function onDragEnd(result) {
        const { source, destination } = result;

        // dropped outside the list
        if (!destination) {
          return;
        }
        const sInd = +source.droppableId;
        const dInd = +destination.droppableId;

        if (sInd === dInd) {
          const items = reorder(state[sInd], source.index, destination.index);
          const newState = [...state];
          newState[sInd] = items;
          setState(newState);
        } else {
          const result = move(state[sInd], state[dInd], source, destination);
          const newState = [...state];
          newState[sInd] = result[sInd];
          newState[dInd] = result[dInd];

          setState(newState.filter((group) => group.length));
        }
      }

      return (
        <div>
          <button
            type="button"
            onClick={() => {
              setState([...state, []]);
            }}
          >
            Add new group
          </button>
          <button
            type="button"
            onClick={() => {
              setState([...state, getItems(1)]);
            }}
          >
            Add new item
          </button>
          <div style={{ display: 'flex' }}>
            <DragDropContext onDragEnd={onDragEnd}>
              {state.map((el, ind) => (
                <Droppable key={ind} droppableId={`${ind}`}>
                  {(provided, snapshot) => (
                    <div
                      ref={provided.innerRef}
                      style={getListStyle(snapshot.isDraggingOver)}
                      {...provided.droppableProps}
                    >
                      {el.map((item, index) => (
                        <Draggable key={item.id} draggableId={item.id} index={index}>
                          {(provided, snapshot) => (
                            <div
                              ref={provided.innerRef}
                              {...provided.draggableProps}
                              {...provided.dragHandleProps}
                              style={getItemStyle(snapshot.isDragging, provided.draggableProps.style)}
                            >
                              <div
                                style={{
                                  display: 'flex',
                                  justifyContent: 'space-around',
                                }}
                              >
                                {item.content}
                                <button
                                  type="button"
                                  onClick={() => {
                                    const newState = [...state];
                                    newState[ind].splice(index, 1);
                                    setState(newState.filter((group) => group.length));
                                  }}
                                >
                                  delete
                                </button>
                              </div>
                            </div>
                          )}
                        </Draggable>
                      ))}
                      {provided.placeholder}
                    </div>
                  )}
                </Droppable>
              ))}
            </DragDropContext>
          </div>
        </div>
      );
    }

    export default DynamicDrag;

两个项目之间的拖拽

    import React, { useState } from 'react';
    import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd';

    // fake data generator
    const getItems = (count, offset = 0) =>
      Array.from({ length: count }, (v, k) => k).map((k) => ({
        id: `item-${k + offset}`,
        content: `item ${k + offset}`,
      }));

    // a little function to help us with reordering the result
    const reorder = (list, startIndex, endIndex) => {
      const result = Array.from(list);
      const [removed] = result.splice(startIndex, 1);
      result.splice(endIndex, 0, removed);

      return result;
    };

    /**
     * Moves an item from one list to another list.
     */
    const move = (source, destination, droppableSource, droppableDestination) => {
      const sourceClone = Array.from(source);
      const destClone = Array.from(destination);
      const [removed] = sourceClone.splice(droppableSource.index, 1);

      destClone.splice(droppableDestination.index, 0, removed);

      const result = {};
      result[droppableSource.droppableId] = sourceClone;
      result[droppableDestination.droppableId] = destClone;

      return result;
    };

    const grid = 8;

    const getItemStyle = (isDragging, draggableStyle) => ({
      // some basic styles to make the items look a bit nicer
      userSelect: 'none',
      padding: grid * 2,
      margin: `0 0 ${grid}px 0`,

      // change background colour if dragging
      background: isDragging ? 'lightgreen' : 'grey',

      // styles we need to apply on draggables
      ...draggableStyle,
    });

    const getListStyle = (isDraggingOver) => ({
      background: isDraggingOver ? 'lightblue' : 'lightgrey',
      padding: grid,
      width: 250,
    });

    const Nest = ()=> {
      // state = {
      //   items: getItems(10),
      //   selected: getItems(5, 10),
      // };
      const [state, setState] = useState({
        items: getItems(10),
        selected: getItems(5, 10),
      })
      /**
       * A semi-generic way to handle multiple lists. Matches
       * the IDs of the droppable container to the names of the
       * source arrays stored in the state.
       */
      const id2List = {
        droppable: 'items',
        droppable2: 'selected',
      };

      const getList = (id) => state[id2List[id]];

      const onDragEnd = (result) => {
        const { source, destination } = result;

        // dropped outside the list
        if (!destination) {
          return;
        }

        if (source.droppableId == destination.droppableId) {

          const items = reorder(getList(source.droppableId), source.index, destination.index);

          let stateItem = { items };

          if (source.droppableId === 'droppable2') {
            stateItem = { selected: items };
          }

          setState({...state, ...stateItem});
        } else {
          const result = move(
            getList(source.droppableId),
            getList(destination.droppableId),
            source,
            destination,
          );

          setState({
            items: result.droppable,
            selected: result.droppable2,
          });
        }
      };

      // Normally you would want to split things out into separate components.
      // But in this example everything is just done in one place for simplicity
        return (
          <DragDropContext onDragEnd={onDragEnd}>
            <Droppable droppableId="droppable">
              {(provided, snapshot) => (
                <div ref={provided.innerRef} style={getListStyle(snapshot.isDraggingOver)}>
                  {state.items?.map((item, index) => (
                    <Draggable key={item.id} draggableId={item.id} index={index}>
                      {(provided, snapshot) => (
                        <div
                          ref={provided.innerRef}
                          {...provided.draggableProps}
                          {...provided.dragHandleProps}
                          style={getItemStyle(snapshot.isDragging, provided.draggableProps.style)}
                        >
                          {item.content}
                        </div>
                      )}
                    </Draggable>
                  ))}
                  {provided.placeholder}
                </div>
              )}
            </Droppable>
            <Droppable droppableId="droppable2">
              {(provided, snapshot) => (
                <div ref={provided.innerRef} style={getListStyle(snapshot.isDraggingOver)}>
                  {state.selected?.map((item, index) => (
                    <Draggable key={item.id} draggableId={item.id} index={index}>
                      {(provided, snapshot) => (
                        <div
                          ref={provided.innerRef}
                          {...provided.draggableProps}
                          {...provided.dragHandleProps}
                          style={getItemStyle(snapshot.isDragging, provided.draggableProps.style)}
                        >
                          {item.content}
                        </div>
                      )}
                    </Draggable>
                  ))}
                  {provided.placeholder}
                </div>
              )}
            </Droppable>
          </DragDropContext>
        );

    }

    export default Nest;

拖拽投票组件,拖动至指定容器,位置互换

    /**
     * @file 拖拽投票组件
     * @description 拖动至指定容器,单位互换
     * @author tiandisheng
     * date 2020-07-03
     * */

    import React from 'react';
    import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd';
    import { countyUnits } from './constant';
    import styles from './VoteByDnd.less';

    const grid = 8;

    /**
     * @function 获取droppableId中位置索引
     * @param {string} droppableId
     * @returns {number} droppableIndex
     * */
    const getIndex = (droppableId) => {
      const endDroppableIdArray = droppableId.split('-');
      const droppableIndex = parseInt(endDroppableIdArray[2], 10);
      return droppableIndex;
    };

    /**
     * @function 生成排序后的数组
     * @description 根据容器droppableId内拼接的索引确定索引
     * @param {array} list 排序前数组
     * @param {number} startDroppablDeId 元素在被拖动前所在容器id
     * @param {number} endDroppablDeId 元素在被拖动后位置所在容器id
     * @return {array} result 排序后数组
     * */
    const reorder = (list, startDroppablDeId, endDroppablDeId) => {
      const result = JSON.parse(JSON.stringify(list)); // 此处需要深拷贝
      const startIndex = getIndex(startDroppablDeId);
      const endIndex = getIndex(endDroppablDeId);

      // 交换逻辑

      result[startIndex] = list[endIndex];
      result[endIndex] = list[startIndex];

      // 插入逻辑
      // if (startIndex > endIndex) {
      //   result.splice(endIndex, 0, list[startIndex]); // 指定位置插入新增项目
      //   result.splice(startIndex + 1, 1); // 删除指定项目
      // } else {
      //   result.splice(endIndex + 1, 0, list[startIndex]); // 指定位置插入新增项目
      //   result.splice(startIndex, 1); // 删除指定项目
      // }

      return result;
    };

    /**
     * @function 设置样式
     * @param {boolean} isDragging 是否在拖拽状态;
     * @param {object} draggableStyle
     * @returns {object} styleOnject 存储样式的对象
     * */
    const setItemStyle = (isDragging, draggableStyle) => {
      const styleOnject = {
        // some basic styles to make the items look a bit nicer 一些基本的样式可以让衣服看起来更好看
        userSelect: 'none',
        padding: grid * 2,
        margin: `0 0 ${grid}px 0`,
        width: 70,
        height: 70,
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'center',
        transition: 'all 0.5s',
        // background: '#33333',
        // 拖拽的时候背景变化
        opacity: isDragging ? '1' : '0',
        backgroundColor: isDragging ? 'rgba(93,173,243,0.5)' : 'rgba(93,173,243,1)',
        // styles we need to apply on draggables 我们需要应用于拖放的样式
        ...draggableStyle,
      };
      return styleOnject;
    };

    class VoteByDnd extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
          items: countyUnits,
        };
        this.onDragEnd = this.onDragEnd.bind(this);
      }

      onDragEnd(result) {
        console.log('拖拽结束result', result);
        if (!result.destination) {
          return;
        }
        const { items: prevItems } = this.state;
        const items = reorder(prevItems, result.source.droppableId, result.destination.droppableId);
        this.setState({
          items,
          isDragging: false,
        });
      }

      onDragStart = (result) => {
        console.log('拖拽开始result', result);
        this.setState({
          isDragging: true,
        });
      };

      /**
       * @function 渲染子拖拽元素
       * */
      renderChildDrag = (item, index) => {
        const childElement = (
          <Droppable droppableId={`child-droppable-${index}`}>
            {(provided, snapshot) => (
              <div
                //provided.droppableProps应用的相同元素.
                {...provided.droppableProps}
                // 为了使 droppable 能够正常工作必须 绑定到最高可能的DOM节点中provided.innerRef.
                ref={provided.innerRef}
                // style={getListStyle(snapshot)}
                // className={isDragging ? styles.childBoxHidden : styles.childBoxShow}
                className={styles.childBoxShow}
              >
                <Draggable key={index} draggableId={`child-draggableId-${index}`} index={index}>
                  {(provided, snapshot) => (
                    <div
                      ref={provided.innerRef}
                      {...provided.draggableProps}
                      {...provided.dragHandleProps}
                      style={setItemStyle(snapshot.isDragging, provided.draggableProps.style)}
                    >
                      {`${item}`}
                    </div>
                  )}
                </Draggable>
                {provided.placeholder}
              </div>
            )}
          </Droppable>
        );
        return childElement;
      };

      render() {
        return (
          <div className={styles.root}>
            <DragDropContext onDragEnd={this.onDragEnd} onDragStart={this.onDragStart}>
              <Droppable droppableId="droppable" type="father">
                {(provided, snapshot) => (
                  <div
                    //provided.droppableProps应用的相同元素.
                    {...provided.droppableProps}
                    // 为了使 droppable 能够正常工作必须 绑定到最高可能的DOM节点中provided.innerRef.
                    ref={provided.innerRef}
                    // style={getListStyle(snapshot)}
                    className={styles.flexBox}
                  >
                    {this.state.items.map((item, index) => (
                      <Draggable key={index} draggableId={`index`} index={index} isDragDisabled>
                        {(provided, snapshot) => (
                          <div
                            ref={provided.innerRef}
                            {...provided.draggableProps}
                            {...provided.dragHandleProps}
                            className={styles.flexItem}
                          >
                            <div className={styles.tempTitle}> {item} </div>
                            {this.renderChildDrag(item, index)}
                          </div>
                        )}
                      </Draggable>
                    ))}
                    {provided.placeholder}
                  </div>
                )}
              </Droppable>
            </DragDropContext>
          </div>
        );
      }
    }

    export default VoteByDnd;
    const countyUnitsString ='上城、下城、江干、拱墅、西湖、滨江、钱塘、景区、萧山、余杭、富阳、临安、桐庐、淳安、建德';

    export const countyUnits = countyUnitsString.split('、');
    .root {
      .flexBox {
        display: flex;
        flex-wrap: wrap;
        width: 400px;
        .flexItem {
          position: relative;
          display: flex;
          align-items: center;
          justify-content: center;
          width: 90px;
          height: 90px;
          margin: 0 10px 10px 0;
          color: #fff;
          font-size: 18px;
          background-color: #5dadf3;
        }
      }
      .tempTitle {
        position: absolute;
      }
      .childBoxShow {
        width: 90px;
        height: 90px;
        opacity: 1;
      }
    }

转载:tiandisheng.top/dragdemo/co…