前端实现伸缩框

本文,我们讲讲前端怎么实现伸缩框的功能,类似下面👇

案例验证的浏览器为 - Google Chrome 版本 119.0.6045.123(正式版本)(arm64)

前言

在实际的工作中,我们有遇到这么一个实用的需求:

允许用户对内容框进行伸缩

咦,这不是很简单的事情?

So EASY~

我们使用 resize 这个 css 样式不就得了。

CSS 中使用 resize

是的,我们可以通过 resize 这个属性来实现伸缩框的功能。比如这样👇我们设定 resize: both;

html 复制代码
<div class="resize-both">
  resize both
</div>
css 复制代码
:root {
  --primary-color: #3498db;
}
.resize-both {
  width: 100px;
  height: 100px;
  border: 1px solid var(--primary-color);
  /* resize */
  resize: both;
  overflow: hidden;
}

resize 需要配合 overflow 属性来使用,属性值为 visible 不生效

实现的效果如下:

当然,我们这里只是以 resize: both; 为案例,我们可以设定其横向或者竖向的伸缩 - mdn web docs - resize

嗯,resize 确实实现了我们的伸缩框功能。但是,我们是否可以改变下右下角的 icon 图表呢?是否可以更改图标所在的位置呢?这对我们很不友好 -> Is there a way to change the CSS resize corner's position?

So,目前来看,我们只能接受使用 resize 的默认。

那么,我们能否自己来编写伸缩款呢?

能的 ,我们用 javascript 来实现个 resize bothgif 图的功能。

JS 实现伸缩框

我们的思路是这样子的:

  • 实现右下角的三角拖动图标
  • 计算伸缩框距离左边和顶部的距离
  • 监听鼠标的点击、拖动、抬起事件,记录鼠标当前相对视窗左上角点的左侧距离和顶部距离
  • 计算鼠标距离边框左侧的距离,即边框的新宽度
  • 计算鼠标距离边框顶部的距离,即边框的新高度
  • 限定边框的最小距离,防止 icon 拖动隐藏

我们需要跟浏览器的事件打交道,这里引入 RxJS ,(当然,读者可以手写原生 javascript)。

RxJS 是一个用于处理异步事件流的库。

在开始之前,我们还得熟悉下juejin.cn/post/708512...中的 Element.getBoundingClientRect() 方法:

我们可以通过这个方法获取元素其左上角顶点相对可视窗口的坐标(x, y)及其元素的宽度和高度。

当然,我们还需要通过 event.clienXevent.clientY 获取当前鼠标距离可视窗口的坐标(clientX, clientY)

Ok,万事俱备,我们来实现下:

html 复制代码
<div class="rxjs-both" id="rxjs-both">
  rxjs both
  <div class="icon-resize" id="icon-resize"></div>
</div>

类名为 icon-resize 的元素是用来实现右下角的三角图标的,这里我们结合 css 中的伪元素来实现:

css 复制代码
:root {
  --primary-color: #3498db;
  --icon-color: #666;
}
.rxjs-both {
  width: 100px;
  height: 100px;
  border: 1px solid var(--primary-color);
  margin-left: 400px;
  position: relative;
  overflow: hidden;
}
.icon-resize {
  width: 10px;
  height: 10px;
  position: absolute;
  bottom: 0;
  right: 0;
  /* 更改了 cusor 图标 */
  cursor: nwse-resize;
}
.icon-resize::before {
  content: "";
  display: block;
  width: 10px;
  height: 1px;
  background-color: var(--icon-color);
  position: absolute;
  top: 50%;
  transform: translateY(-50%) rotate(135deg);
}
.icon-resize::after {
  content: "";
  display: block;
  width: 5px;
  height: 1px;
  background-color: var(--icon-color);
  position: absolute;
  top: 75%;
  left: 75%;
  transform: translate(-50%, -50%) rotate(135deg);
}

页面的效果如下:

接着,我们添加 javascript 让页面动起来:

javascript 复制代码
const { fromEvent } = rxjs;
const { mergeMap, takeUntil } = rxjs.operators;

const resizableDiv = document.getElementById('rxjs-both');

function handleMouseMove(event) {
  let boundingEl = resizableDiv.getBoundingClientRect();
  let _width = event.clientX - boundingEl.left; // 获取拖动后的宽度
  let _height = event.clientY - boundingEl.top; // 获取拖动后的高度
  resizableDiv.style.width = (_width >= 20 ? _width : 20) + 'px';
  resizableDiv.style.height = (_height >= 20 ? _height : 20) + 'px';
}

const mouseMove$ = fromEvent(document, 'mousemove'); // fromEvent 创建可观察对象 Observable
const mouseUp$ = fromEvent(document, 'mouseup');

const drag$ = fromEvent(document.getElementById('icon-resize'), 'mousedown').pipe(
  mergeMap(() => mouseMove$.pipe(takeUntil(mouseUp$))) // 鼠标抬起结束监听
);

drag$.subscribe(handleMouseMove); // 观察者 -> 鼠标拖动的过程中监听

这里我们引入的 rxjs7.8.1 版本,读者可以直接使用 cdn -> https://cdn.bootcdn.net/ajax/libs/rxjs/7.8.1/rxjs.umd.js。当鼠标按下拖动的时候,触发对伸缩框的宽度和高度的重新计算并赋值。当鼠标抬起后,结束监听。

实现的效果可以说和 CSS 实现的 resize: both 的大同小异,优雅且丝滑~ 如下:

是的,这里我们实现了拉取右下角的图标实现对伸缩框的高度和宽度做了更改。其实,是否更改宽度或者高度,是否更改图标的位置,或者是否通过拉取边框进行伸缩?原理都一样,读者感兴趣的话,可以自行实现~

总结

我们实验了两种的伸缩方法:

  • CSSresize 结合 overflow 来实现,虽然能够完成任务,但是太固化,适合不讲究页面布局的时候实现
  • JS 方式实现,引入了 RxJS 优雅实现,可对 UI 高度定制化
相关推荐
蜗牛快跑2134 分钟前
面向对象编程 vs 函数式编程
前端·函数式编程·面向对象编程
Dread_lxy5 分钟前
vue 依赖注入(Provide、Inject )和混入(mixins)
前端·javascript·vue.js
涔溪1 小时前
Ecmascript(ES)标准
前端·elasticsearch·ecmascript
榴莲千丞1 小时前
第8章利用CSS制作导航菜单
前端·css
奔跑草-1 小时前
【前端】深入浅出 - TypeScript 的详细讲解
前端·javascript·react.js·typescript
羡与1 小时前
echarts-gl 3D柱状图配置
前端·javascript·echarts
guokanglun1 小时前
CSS样式实现3D效果
前端·css·3d
咔咔库奇1 小时前
ES6进阶知识一
前端·ecmascript·es6
前端郭德纲1 小时前
浏览器是加载ES6模块的?
javascript·算法
JerryXZR1 小时前
JavaScript核心编程 - 原型链 作用域 与 执行上下文
开发语言·javascript·原型模式