对 Ant-design 的 Drawer 组件 增加拖拽效果
创始人
2024-09-26 04:45:33
0

写在前面

Drawer 组件在日常开发中使用的频率还是挺高的,一般情况下,都可以满足我们的日常使用。

最近笔者看到这样的一个需求,就是把 Drawer 改造成可拖拽的效果,因为改成可拖拽的就可以对里面的内容进行自适应的宽度改变,比如 Echarts 图表类的比较适合,拖拽的宽一些可视性会更好。

那话不多少,我们来想一下怎么实现这个功能。

思路

首先先来看一下 Drawer 组件,如果我们想拖拽一定是沿着左边的线去拖拽,或者可以加个图标固定拖拽的位置都可以。

那思路也很简单:

要达到拖拽效果,肯定要满足的是我们的拖拽的距离等于 Drawer 的宽度,只要满足这个条件,那拖拽效果就成立了。 

那现在的问题就转变为怎么求拖拽的距离了。

拖拽距离 = 终止位置 - 起始位置

当按下时,需要记录起始位置,移动过程中记录实时变化的X轴坐标即可。

有了大概思路,现在我们来实现吧。

加边拖动


首先我们需要确定按下的元素,已知我们需要按着左边的边进行移动,也可以用图标代替,现在我们先使用边,图标同理,因为需要给边添加相关事件,这里我们需要添加一个假的边进行实现。

这是我们的原始代码,现在先加边

               

Some contents...

Some contents...

Some contents...

加边的思路是在 Drawer 组件内增加一个容器,将容器的边和 Drawer 组件的边重合即可,此时需要设置 Drawer 组件的 padding 为 0,要不然不会重叠。

      { padding: 0 }}       >         

Some contents...

Some contents...

Some contents...

红色边框就是我们的容器,可以看到已经重叠了 

 

现在还不行,因为我们只想拖拽左边的线,不能对整个容器增加事件,也很简单,再加一条竖线放在左边进行重叠即可。

代码如下:

      { padding: 0 }}         width="auto"       >         

Some contents...

Some contents...

Some contents...

为了展示,现在有些覆盖,后面效果调整宽度和背景色即可。

事件 

现在边已经好了,我们接下来只需要对边增加相关事件即可。

鼠标按下

当鼠标按下时,记录起始位置,拿到 Drawer 组件内容器的开始宽度,同时增加移动和抬起事件,因为后面需要移动元素的。

这里解释一下为什么是拿到 Drawer 组件内容器的宽度,而不是直接设置 Drawer 的宽度,这里我使用的是将 Drawer 的宽度为 auto,通过容器的宽度去撑起 Drawer 的宽度,你也可以直接设置Drawer 的宽度,但是移动过程中会有一些问题,这里就不做演示了,感兴趣的可以试试。

  const startX = useRef(0)   const startWidth = useRef(0)   const onMouseDown = (e: React.MouseEvent) => {     startX.current = e.clientX     startWidth.current = drawerRef.current?.getBoundingClientRect().width || 0     document.addEventListener('mousemove', onMouseMove)     document.addEventListener('mouseup', onMouseUp)   }

鼠标移动

鼠标按下记录起始位置,移动时就需要进行计算了,实时得到移动的距离。

解释一下 newWidth 就是新的宽度,正常情况下应该等于:容器的宽度 + 移动的距离

但也有移动到左侧停止,再往右侧移动的

因为是先往左侧移动,移动得到的差值是负数,所以直接减就行。

如果是移动到左侧停止,再往右侧移动的,那差值是正值,直接减就行了。

  const onMouseMove = (e: MouseEvent) => {     console.log('e.clientX : ', e.clientX)     const newWidth = startWidth.current - (e.clientX - startX.current)     if (drawerRef.current) {       drawerRef.current.style.width = `${newWidth > 0 ? newWidth : 0}px`     }   }

 鼠标抬起

当鼠标抬起时,只需要移除相关事件即可。

  const onMouseUp = useCallback() => {     document.removeEventListener('mousemove', onMouseMove)     document.removeEventListener('mouseup', onMouseUp)   }

初始效果

bug修复

可以看到效果基本实现了,但是有一些小bug

第一:拖拽过程有文字选择效果,不好

解决办法:只需要在鼠标按下事件里增加阻止默认事件,阻止捕获和冒泡阶段中当前事件的进一步传播。

  const onMouseDown = (e: React.MouseEvent) => {     e.preventDefault()     e.stopPropagation()     startX.current = e.clientX     startWidth.current = drawerRef.current?.getBoundingClientRect().width || 0     document.addEventListener('mousemove', onMouseMove)     document.addEventListener('mouseup', onMouseUp)   }

第二:移动到最右侧时,里面的内容容器的宽度还在减小

解决办法:给容器设置宽度以及,最小宽度即可

.drawerContent {   min-width: 200px;   width: 200px;   height: 100%;   border: 1px solid red;   position: relative; } 

再来看看效果,现在上面的问题都没了,还不错

图标拖动

上面我们是通过加边实现的,但往往实际需求中,可能会有其他的方式要求,比如加一个固定的图标或者UI设计的进行拖动,这里我们就加个简单的图标,事件和上面一致。

      { padding: 0 }}       >         
{ fontSize: '50px' }} onMouseDown={onMouseDown}/>

Some contents...

Some contents...

Some contents...

 同时设置样式

.dragLine {     cursor: ew-resize;     width: 50px;     height: 50px;     position: absolute;     top: 43%;     left: -25px; }

但是发现只显示了一半,另一半被遮挡住了

只需要设置Drawer组件的overflow:visible即可

bodyStyle={{ padding: 0, overflow: 'visible' }}

效果一致,大家可以根据自己需求进行更改

Drawer在左侧时

上面说的是 Drawer 在右侧时,现在说一下在左侧时,道理一样,只需要更改按压元素的位置即可移动时计算的距离即可。

定位改到右侧

.dragLine {   cursor: ew-resize;   position: absolute;   top: 50%;   right: -25px; }

往右移动改为加即可

const newWidth = startWidth.current + (e.clientX - startX.current)

效果一致

总结

实现这个需求首先确定按下元素的位置,为按下元素添加相应事件,根据移动的距离动态赋值内容容器的宽度,再根据Drawer的width:auto,自动撑开Drawer组件即可。

当然实现过程中也有其他小 bug,比如选中文字,设置最小宽度等等,其实还有小问题,文章中并没有呈现,就是如果里面的内容时 iframe 引入的话,会导致移动事件失效,这个会单独写一篇文章,主要方便有相同问题的朋友进行搜索解决问题。

全部源码

import React, { useState, useRef, useCallback, useEffect } from 'react' import { Drawer, Button } from 'antd' import '../DraggableDrawer.css' // 为了额外的样式 import { DragOutlined } from '@ant-design/icons'  export default function DrawDemo() {   const [visible, setVisible] = useState(false)   const drawerRef = useRef(null)   const startX = useRef(0)   const startWidth = useRef(0)    const showDrawer = () => {     setVisible(true)   }    const onClose = () => {     setVisible(false)   }   const onMouseDown = (e: React.MouseEvent) => {     e.preventDefault()     e.stopPropagation()     startX.current = e.clientX     startWidth.current = drawerRef.current?.getBoundingClientRect().width || 0     console.log('startWidth.current: ', startWidth.current)     document.addEventListener('mousemove', onMouseMove)     document.addEventListener('mouseup', onMouseUp)   }    const onMouseMove = (e: MouseEvent) => {     const newWidth = startWidth.current - (e.clientX - startX.current)     if (drawerRef.current) {       drawerRef.current.style.width = `${newWidth > 0 ? newWidth : 0}px`     }   }    const onMouseUp = () => {     document.removeEventListener('mousemove', onMouseMove)     document.removeEventListener('mouseup', onMouseUp)   }    return (     <>              { padding: 0, overflow: 'visible' }}       >         
{ fontSize: '50px' }} onMouseDown={onMouseDown} /> {/* */} {/*
*/}
) }

相关内容

热门资讯

安卓10系统更新关闭,全面优化... 你知道吗?最近安卓系统又来了一次大动作,那就是安卓10系统的更新关闭了!这可真是让人有点摸不着头脑,...
安卓系统的文件加密,Andro... 你知道吗?在咱们这个数字化时代,保护隐私和安全变得比以往任何时候都重要。尤其是对于安卓系统用户来说,...
使用安卓系统的费用,全面了解使... 你有没有想过,为什么有些人拿着安卓手机,而有些人却选择了苹果?这其中可不仅仅是品牌喜好那么简单,使用...
vivo用原生安卓系统下载,尽... 你有没有发现,现在手机市场真是热闹非凡,各种品牌争奇斗艳,让人眼花缭乱。不过,今天我要给你安利的,可...
安卓系统好用的桌面时钟,实用好... 你有没有发现,手机里的时钟功能有时候比闹钟还重要呢?想象每天早上被它温柔地叫醒,或者在忙碌的工作间隙...
安卓系统导航车载用优盘,安卓车... 你有没有想过,开车的时候,手机导航虽然方便,但有时候屏幕太小,看不清路线?别急,今天就来给你安利一个...
正确使用电池安卓系统,无忧体验 你知道吗?现在这个智能手机时代,电池续航能力可是大家关注的焦点。尤其是安卓系统用户,电池使用得当与否...
玩吧安卓可以和苹果系统,畅享游... 你知道吗?现在这个时代,手机可是我们生活中不可或缺的好伙伴。不管是安卓还是苹果,它们各有各的特色,各...
安卓系统怎么去掉hd,恢复纯净... 你是不是也和我一样,对安卓手机的系统设置充满了好奇?尤其是那个让人眼花缭乱的“HD”标识,有时候看着...
电脑安卓系统性能表,电脑版性能... 你有没有发现,现在手机电脑的操作系统越来越丰富,尤其是安卓系统,简直就像是个万能的小精灵,啥都能干。...
如何玩转机车安卓系统,玩转机车... 你有没有想过,拥有一台酷炫的机车安卓系统,让你的手机瞬间变身成为一辆会跑的摩托车?想象你可以在手机上...
安卓系统网页怎么回顶部,按钮才... 你是不是在使用安卓系统的手机或平板电脑浏览网页时,不小心翻到了页面底部,现在想回到顶部,却有点摸不着...
为什么安卓系统要认证,安卓系统... 你知道吗?安卓系统最近可是掀起了一阵认证热潮,这可不仅仅是简单的更新换代那么简单哦!为什么安卓系统要...
安卓50原生系统手机,功能革新... 你有没有发现,最近你的安卓手机突然变得不一样了?是不是因为它的系统升级到了安卓50原生系统呢?没错,...
安卓永远比不了的系统,永远无法... 你有没有想过,为什么安卓系统永远比不了某些其他系统呢?是不是每次看到那些流畅无阻、功能强大的设备,心...
安卓8怎么升级11系统,解锁新... 你有没有发现,你的安卓手机已经有点儿“老态龙钟”了?别急,别急,今天就来教你怎么给它来个青春焕发的大...
双系统安卓笔记本,开启移动办公... 你有没有想过,一台既能流畅运行安卓应用,又能轻松驾驭Windows系统的笔记本,会是怎样的体验呢?没...
安卓系统调降噪通透软件,打造清... 你有没有发现,最近你的安卓手机在听音乐或者打电话的时候,声音变得超级清晰,仿佛置身于现场?这可不是你...
安卓系统包后缀名,包后缀名背后... 你有没有发现,每次下载安卓应用时,文件名后面总会有那么几个神秘的字母组合,像是“apk”、“jar”...
安卓系统好用的工作软件,盘点十... 你有没有发现,自从你把手机里的安卓系统升级后,工作效率好像提高了不少呢?今天,就让我来给你细细道来,...