基于react-draggable实现边界拖拽功能

栏目: 服务器 · 发布时间: 4年前

内容简介:博主最近在开发过程中,遇到这样一个小小的需求:左边面板部分支持拖拽功能,可以让用户可以看到完整的目录。Tips:vscode编辑器资源管理器部分也支持拖拽功能,与边界拖拽功能类似。

博主最近在开发过程中,遇到这样一个小小的需求:

左边面板部分支持拖拽功能,可以让用户可以看到完整的目录。

基于react-draggable实现边界拖拽功能

Tips:vscode编辑器资源管理器部分也支持拖拽功能,与边界拖拽功能类似。

2.思考

实现拖拽可以用以下两种方案:

(1)借助于html5中新增拖放相关的api

大致思路:

设置元素可拖放( draggable )=> ondragstart 设定拖放的数据类型和值 => ondragover 设置在何处放置数据 => ondrop 将元素拖放到目的地

其中关于鼠标移动距离的计算可以借用 event.clientX 获取。

(2)借助于插件来实现

博主去github上一顿找,找到一个还不错的插件react-draggable,npm链接。

Tips: react-draggable 的拖拽通过 CSS 中的 transform: translate(x, y) 来实现目标元素的移动。

3.react-draggable使用

(1)安装 react-draggable

$ npm install react-draggable --save
复制代码

(2)引用

import Draggable from 'react-draggable'; 
复制代码

(3)常用props

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)Example

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 ,如下图绿色部分所示:

基于react-draggable实现边界拖拽功能
(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 的小伙伴可以查看链接。

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;
复制代码
拖拽过程中:

拖拽结束:


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

细节决定交互设计的成败

细节决定交互设计的成败

张亮 / 2009-3 / 49.00元

《细节决定交互设计的成败》是一本非常实用的有关软件界面的交互设计和可用性设计方面知识的书籍,通过采用一问一答的形式,你将会有针对性地学习到一些能够很快应用在自己软件开发工作中的细节知识和诀窍。例如,如何减轻用户的等待感,如何预防和减少用户的使用错误等。另外,你会发现阅读《细节决定交互设计的成败》时会非常轻松和愉悦;这是由于《细节决定交互设计的成败》写作上的两个特点:第一,采用较多日常生活中的例子来......一起来看看 《细节决定交互设计的成败》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

SHA 加密
SHA 加密

SHA 加密工具

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试