基於react-draggable實現邊界拖拽功能

1.前言

博主最近在開發過程當中,遇到這樣一個小小的需求:
左邊面板部分支持拖拽功能,能夠讓用戶能夠看到完整的目錄。 css

Tips:vscode編輯器資源管理器部分也支持拖拽功能,與邊界拖拽功能相似。html

2.思考

實現拖拽能夠用如下兩種方案:
(1)藉助於html5中新增拖放相關的api
大體思路:
設置元素可拖放(draggable)=> ondragstart設定拖放的數據類型和值 => ondragover設置在何處放置數據 => ondrop將元素拖放到目的地
其中關於鼠標移動距離的計算能夠借用event.clientX獲取。
(2)藉助於插件來實現
博主去github上一頓找,找到一個還不錯的插件react-draggable,npm連接
vue

Tips:react-draggable的拖拽經過CSS中的transform: translate(x, y)來實現目標元素的移動。html5

3.react-draggable使用

(1)安裝react-draggablereact

$ npm install react-draggable --save
複製代碼

(2)引用git

import Draggable from 'react-draggable'; 
複製代碼

(3)經常使用propsgithub

allowAnyClick: boolean // 默認false,設爲true非左鍵可實現點擊拖拽
axis: string // 'x':x軸方向拖拽、'y':y軸方向拖拽、'none':禁止拖拽
bouds: { left: number, top: number, right: number, bottom: number } | string 
    // 限定移動的邊界,接受值:
    //(1)'parent':在移動元素的offsetParent範圍內
    //(2)一個選擇器,在指定的Dom節點內
    //(3){ left: number, top: number, right: number, bottom: number }對象,限定每一個方向能夠移動的距離
cancel:制定給一個選擇器組織drag初始化,例如'.body'
defaultClassName:string // 拖拽ui類名,默認'react-draggable'
drfaultClassNameDragging:string // 正在拖拽ui類名,默認'eact-draggable-dragging'
defaultClassNameDragged:string //拖拽後的類名,默認'react-draggable-dragged'
defaultPosition:{ x: number, y: number } // 起始x和y的位置
disabled:boolean // true禁止拖拽任何元素
grid:[number, number] // 正在拖拽的網格範圍
handle:string // 初始拖拽的的選擇器'.handle'
offsetParent:HTMLElement // 拖拽的offsetParent
onMouseDown: (e: MouseEvent) => void // 鼠標按下的回調
onStart: DraggableEventHandler // 開始拖拽的回調
onDrag:DraggableEventHandler // 拖拽時的回調
onStop:DraggableEventHandler // 拖拽結束的回調
position: {x: number, y: number} // 控制元素的位置
positionOffset: {x: number | string, y: number | string} // 相對於起始位置的偏移
scale:number // 定義拖拽元素的縮放
複製代碼

(4)Examplenpm

class App extends React.Component {
  eventLogger = (e: MouseEvent, data: Object) => {
    console.log('Event: ', e);
    console.log('Data: ', data);
  };
  render() {
    return (
      <Draggable
        axis="x"
        handle=".handle"
        defaultPosition={{x: 0, y: 0}}
        position={null}
        grid={[25, 25]}
        scale={1}
        onStart={this.handleStart}
        onDrag={this.handleDrag}
        onStop={this.handleStop}>
        <div>
          <div className="handle">Drag from here</div>
          <div>This readme is really dragging on...</div>
        </div>
      </Draggable>
    );
  }
}
複製代碼

4.實現

4.1思路

(1)左右box最好採用flex佈局,左邊box初始width設爲Npx,右邊box width爲calc(100% - Npx)
(2)在左邊box內部設置一個拖拽的邊界(drag-box),寬度爲5pxbackground-color設爲transparentcursor設爲col-resiz,以下圖綠色部分所示: api

(3)採用react-draggable包裹drag-box 沿x軸方向移動,設定可拖拽的範圍,移動時設置 background-color爲可見色,同時更新左右box的 width便可,拖拽結束drag-box background-color重置爲 transparent

4.2代碼實現

       代碼中引用了styled-components,這是一款是針對React寫的一套css in js框架,簡單來說就是在js中寫css,能夠輕易實現組件css模塊化,相似於vue組件中給style添加了scoped屬性。 想要學習styled-components的小夥伴能夠查看連接bash

import React, { Component } from 'react';
import Draggable from 'react-draggable';
import styled from 'styled-components';

// 容器
const Container = styled.div`
  display: flex;
  justify-content: flex-start;
`;

// 左邊內容部分
const LeftContent = styled.div`
  position: relative;
  width: ${props => props.width}px;
  height: 100vh;
  padding: 20px;
  background-color: #E6E6FA;
  overflow: hidden;
  flex-grow:1;
`;

// 拖拽部分
const DraggableBox = styled.div`
  position: absolute;
  left: ${props => props.left}px;
  top: 0;
  width: 5px;
  height: 100vh;
  background-color: ${props => props.background};
  cursor: col-resize;
  z-index: 1000;
`;

// 右邊內容部分
const RightContent = styled.div`
  width: calc(100% - ${props => props.leftBoxWidth}px);
  height: 100vh;
  padding: 20px;
  background-color: #FFF;
  flex-grow:1;
  z-index: 100;
`;

const Li = styled.li`
  white-space: nowrap;
`;

class DraggableExp extends Component {
  state = {
    initialLeftBoxWidth: 150, // 左邊區塊初始寬度
    leftBoxWidth: 150, // 左邊區塊初始寬度
    leftBoxMinWidth: 100, // 左邊區塊最小寬度
    leftBoxMaxWidth: 300, // 左邊區塊最大寬度
    dragBoxBackground: 'transparent' // 拖拽盒子的背景色
  }

  // 拖動時設置拖動box背景色,同時更新左右box的寬度
  onDrag = (ev, ui) => {
    const { initialLeftBoxWidth } = this.state;
    const newLeftBoxWidth = ui.x + initialLeftBoxWidth;
    this.setState({
      leftBoxWidth: newLeftBoxWidth,
      dragBoxBackground: '#FFB6C1'
    });
  };

  // 拖拽結束,重置drag-box的背景色
  onDragStop = () => {
    this.setState({
      dragBoxBackground: 'transparent'
    });
  };

  render() {
    const { initialLeftBoxWidth, 
            leftBoxWidth, 
            leftBoxMinWidth, 
            leftBoxMaxWidth, 
            dragBoxBackground } = this.state;
    return (
      <Container>
        <LeftContent width={leftBoxWidth}>
          <h3 style={{paddingLeft: 20}}>目錄</h3>
          <ul>
            <Li>目錄1</Li>
            <Li>目錄2</Li>
            <Li>目錄3</Li>
            <Li>這是個很是長很是長很是長的目錄</Li>
          </ul>
          <Draggable 
            axis="x"
            defaultPosition={{ x: 0, y: 0 }}
            bounds={{ left: leftBoxMinWidth - initialLeftBoxWidth, right: leftBoxMaxWidth - initialLeftBoxWidth }}
            onDrag={this.onDrag}
            onStop={this.onDragStop}>
            <DraggableBox
              left={initialLeftBoxWidth - 5} 
              background={dragBoxBackground} />
          </Draggable>
        </LeftContent>
        <RightContent leftBoxWidth={leftBoxWidth}>
          <h3>這裏是內容塊</h3>
        </RightContent>
      </Container>
    )
  }
}

export default DraggableExp;
複製代碼

4.3實現效果

起始狀態:

拖拽過程當中:
拖拽結束:

以上就是博主借用react-draggable實現邊界拖拽的小功能,感興趣的小夥伴能夠本身動手嘗試一下。 (以爲不錯的小夥伴能夠給文章點個贊,碼字不易,灰常感謝^_^)

相關文章
相關標籤/搜索