前言

本例是在React中实现,不过改一改通过原生js也很好实现,另外兼容性也做到了IE9。(IE8讲道理也是可以的)。

首先看一下需要实现的需求:

要拖动图中的白色横条调整绿色和蓝色区域的高度,要拖动白色竖条调整左边区域和红色区域的宽度。

一两年前曾经遇到过这个需求,当时直接在网上搜了个解决方案贴上去了,不过那个解决方案很挫。

这次的项目又遇到这个需求,而且是三个块的拖动。不仅需要左右拖动还需要上下拖动。

在这里特地记录下解决方案,也希望可以得到一些反馈与优化。

方案的思路

横条拖动和竖条拖动原理差不多,那就先来实现竖条左右拖动调整宽度。

水平方向的布局是通过以下方式实现:

.left{
width: 500px;
height: 100%;
float: left;
position: relative;
} .v-resize{
height: 100%;
width: 4px;
position: absolute;
background: #fff;
left: 500px;
z-index: 2;
cursor: col-resize;
user-select: none;
} .right{
margin-left: 504px;
background-color: lightsalmon;
height: 100%;
}

通过样式我们可以了解到,只要同时改变left块的宽度,白色竖条v-resize的left定位和right块的定位(这个数相差不大,我们将这个数定义为vNum),即可实现水平拖动的效果。

通过鼠标按下白色竖条,开启水平拖动,监控鼠标位置,计算vNum,在鼠标放开或者鼠标移出拖动区域时停止水平拖动。

计算vNum的本质实际上就是通过鼠标位置减去拖动区域离浏览器左侧位置,从而得到vNum。

因为每块区域都有最大和最小宽度的限制,这里仅仅加了个vNumLimit来进行限制,即竖条最少要离最左侧和最右侧的距离。

这里还要考虑到每次窗口resize时,各个参数可能都会有所调整,所以加了窗口resize的处理,当然也加了防抖。

本来想要分步讲解,但是冬寒人乏,懒病发作。

方案的实现

jsx部分

import React, { Component } from 'react'
import _ from 'underscore'
import styles from './index.css' // 可调整宽高的Div
export default class ResizeDiv extends Component {
state = {
isHResize: false,
isVResize: false,
hNum: 100,
vNum: 500,
hNumLimit: 30,
vNumLimit: 30
} resizeOffsetInfo = {
clientTop: 0,
clientLeft: 0
} leftHeight = 0 containerWidth = 0 componentDidMount() {
this.initResizeInfo()
const throttled = _.throttle(() => {
this.initResizeInfo()
}, 200) window.onresize = throttled
}
componentWillUnmount() {
window.onresize = null
} /**
* 初始化resize信息
*/
initResizeInfo = () => {
const hEle = document.getElementById('h_resize_container')
this.resizeOffsetInfo = this.getEleOffset(hEle)
this.leftHeight = hEle.offsetHeight
this.containerWidth = document.getElementById('v_resize_container').offsetWidth
} /**
* 获取元素的偏移信息
*/
getEleOffset(ele) {
var clientTop = ele.offsetTop
var clientLeft = ele.offsetLeft
let current = ele.offsetParent
while (current !== null) {
clientTop += current.offsetTop
clientLeft += current.offsetLeft
current = current.offsetParent
}
return {
clientTop,
clientLeft,
height: ele.offsetHeight,
width: ele.offsetWidth
}
} /**
* 开始拖动水平调整块
*/
hResizeDown = () => {
this.setState({
isHResize: true
})
} /**
* 拖动水平调整块
*/
hResizeOver = (e) => {
const { isHResize, hNum, hNumLimit } = this.state
if (isHResize && hNum >= hNumLimit && (this.resizeOffsetInfo.height - hNum >= hNumLimit)) {
let newValue = this.resizeOffsetInfo.clientTop + this.resizeOffsetInfo.height - e.clientY
if (newValue < hNumLimit) {
newValue = hNumLimit
}
if (newValue > this.resizeOffsetInfo.height - hNumLimit) {
newValue = this.resizeOffsetInfo.height - hNumLimit
}
this.setState({
hNum: newValue
})
}
} /**
* 开始拖动垂直调整块
*/
vResizeDown = () => {
this.setState({
isVResize: true
})
} /**
* 拖动垂直调整块
*/
vResizeOver = (e) => {
const { isVResize, vNum, vNumLimit } = this.state
if (isVResize && vNum >= vNumLimit && (this.containerWidth - vNum >= vNumLimit)) {
let newValue = e.clientX - this.resizeOffsetInfo.clientLeft
if (newValue < vNumLimit) {
newValue = vNumLimit
}
if (newValue > this.containerWidth - vNumLimit) {
newValue = this.containerWidth - vNumLimit
}
this.setState({
vNum: newValue
})
}
} /**
* 只要鼠标松开或者离开区域,那么就停止resize
*/
stopResize = () => {
this.setState({
isHResize: false,
isVResize: false
})
} render() {
const hCursor = this.state.isHResize ? 'row-resize' : 'default'
const hColor = this.state.isHResize ? '#ddd' : '#fff'
const vCursor = this.state.isVResize ? 'col-resize' : 'default'
const vColor = this.state.isVResize ? '#ddd' : '#fff' return (
<div className={styles['container']} onMouseUp={this.stopResize} onMouseLeave={this.stopResize}>
<div id='v_resize_container' className={styles['content']} onMouseMove={this.vResizeOver}>
<div id='h_resize_container' style={{ width: this.state.vNum, cursor: vCursor }} className={styles['left']}
onMouseMove={this.hResizeOver}>
<div style={{ bottom: this.state.hNum, cursor: hCursor }} className={styles['left-top']}>aasd</div>
<div style={{ bottom: this.state.hNum, backgroundColor: hColor }} draggable={false} onMouseDown={this.hResizeDown} className={styles['h-resize']} />
<div style={{ height: this.state.hNum + 4, cursor: hCursor }} className={styles['left-bottom']}>asd</div>
</div>
<div style={{ left: this.state.vNum, backgroundColor: vColor }} draggable={false} onMouseDown={this.vResizeDown} className={styles['v-resize']} />
<div style={{ marginLeft: this.state.vNum + 4, cursor: vCursor }} className={styles['right']}>
asdas
</div>
</div>
</div>
)
}
}

css部分

.container{
margin: 30px;
overflow: hidden;
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
} .content{
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
min-height: 300px;
} .left{
width: 500px;
height: 100%;
float: left;
position: relative;
} .left-top{
position: absolute;
top: 0;
bottom: 104px;
width: 100%;
background-color: lightblue;
} .h-resize{
height: 4px;
width: 100%;
background: #fff;
position: absolute;
bottom: 100px;
z-index: 1;
cursor: row-resize;
user-select: none;
} .left-bottom{
position: absolute;
bottom: 0;
width: 100%;
height: 100px;
background-color: lightgreen;
} .v-resize{
height: 100%;
width: 4px;
position: absolute;
background: #fff;
left: 500px;
z-index: 2;
cursor: col-resize;
user-select: none;
} .right{
margin-left: 504px;
background-color: lightsalmon;
height: 100%;
}

总结

技术上其实还是比较简单的,不过丝般润滑的左右移动还是挺有成就感的。

如果有更好的玩法还望不吝赐教。

这是这个demo的地址:demo地址

实现可调整宽高的DIV(左右拖动和上下拖动)的更多相关文章

  1. 不定宽高的DIV,垂直水平居中

    1.怎么让一个不定宽高的DIV,垂直水平居中? 答:1)使用CSS方法. 父盒子设置: display:table-cell; text-align:center; vertical-align:mi ...

  2. 固定宽高的DIV绝对居中示例

    看了一些代码,然后自己试验了一番,分享如下示例: 实现点: 如果元素的宽高固定,那么,css指定样式为top:50%;left:50%; 而margin-top和 margin-left 指定为负数, ...

  3. css实现不定宽高的div水平、垂直居中

    一共有三个方案: 1,第一种方案主要使用了css3中transform进行元素偏移,效果非常好 这方法功能很强大,也比较灵活,不仅仅局限在实现居中显示.  兼容方面也一样拿IE来做比较,第二种方法IE ...

  4. 已知宽高和未知宽高的div块的水平垂直居中

    //已知宽高的情况 .div1_container{     border:1px solid #00ee00;     height:300px;     position:relative; } ...

  5. 怎么让一个不定宽高的div垂直水平居中?

    方法一:使用CSS3 transform 父盒子设置:position:relative; div设置:position:absolute;transform:translate(-50%,-50%) ...

  6. handsontable组件和jqwidgets(jqxdragdrop组件)在一个页面产生调整宽高bug

    修改handsontable.full.js handsontable绑定的"mouseup"事件,默认是window区域太大.引起冲突.

  7. 写个js动态调整图片宽高 (原创)

    <body style="TEXT-ALIGN: center;"> <div id="testID" style="backgro ...

  8. css实现div不定宽高垂直水平居中解决方案

    在项目中我们经常能碰见然图片垂直水平居中,不定宽高的div垂直水平居中,等等~~ 现在我将介绍我所知道的几种用css来解决的几种方案. 1.父元素text-align:center;display:t ...

  9. iview Carousel 轮播图自适应宽高;iview 轮播图 图片重叠问题;iview tabs 高度互相影响问题;vue this问题;

    最终效果图: 一.轮播图中图片自适应宽高:  <Carousel loop v-bind:height="imgHeight+'px'" v-model="caro ...

随机推荐

  1. github提交代码失败

    向github上面提交代码,提示代码里面有大文件,建议使用git-lfs. 1,安装git-lfs yum install git-lfs 2,配置需要追踪的打文件(由于我这里提交的是jar包) gi ...

  2. iOS开发创建UI的耗时操作处理

    项目中有网络请求.读写操作等一系列耗时操作时,为了避免阻塞主线程,我们会把这些耗时操作放到子线程中去处理,当处理完成后,再回到主线程更新UI,这样就不会阻塞主线程.但是创建UI的时候一般都是在主线程中 ...

  3. shell的case用法

    今天给大家简单介绍一下结构条件语句的用法,实际上就是规范的多分支if语句,如下: case语法: case "字符串变量" in 值1)指令1... ;; 值2)指令2... ;; ...

  4. adb入门学习笔记

    连接模拟器(模拟器桥接模式) 使用adb devices列出已连接到工作站的设备. 使用adb shell 启动设备或模拟器上的shell. 列出设备已安装的所有软件包 将电脑文件移动到手机模拟器上( ...

  5. C++多线程同步技巧(三)--- 互斥体

    简介 Windows互斥对象机制. 只有拥有互斥对象的线程才有访问公共资源的权限,因为互斥对象只有一个,所以能保证公共资源不会同时被多个线程访问,在线程同步与保证程序单体运行上都有相当大的用处. 代码 ...

  6. Java多线程(五)线程的生命周期

    点我跳过黑哥的卑鄙广告行为,进入正文. Java多线程系列更新中~ 正式篇: Java多线程(一) 什么是线程 Java多线程(二)关于多线程的CPU密集型和IO密集型这件事 Java多线程(三)如何 ...

  7. sboot mybatis

    https://www.cnblogs.com/lspz/p/6723603.html spring.datasource.url=jdbc:mysql://10.46.52.205:3306/tes ...

  8. MySQL高级知识(四)——Explain

    前言:explain(执行计划),使用explain关键字可以模拟优化器执行sql查询语句,从而知道MySQL是如何处理sql语句.explain主要用于分析查询语句或表结构的性能瓶颈. 注:本系列随 ...

  9. CF917D Stranger Trees

    CF917D Stranger Trees 题目描述 给定一个树,对于每个\(k=0,1\cdots n-1\),问有多少个生成树与给定树有\(k\)条边重合. 矩阵树定理+高斯消元 我们答案为\(f ...

  10. [matlab] 6.粒子群优化算法

    粒子群优化(PSO, particle swarm optimization)算法是计算智能领域,除了蚁群算法,鱼群算法之外的一种群体智能的优化算法,该算法最早由Kennedy和Eberhart在19 ...