假设我们要将以下元素变成可拖动元素:
<div id="resizeMe" class="resizable">Resize me</div>
首先,我们需要准备一些指示元素可调整大小的元素。它们绝对放置在原始元素的四个侧面。
为了演示简单,这里只准备了两个元素,分别放在右侧和底部:
<div id="resizeMe" class="resizable">
Resize me
<div class="resizer resizer-r"></div>
<div class="resizer resizer-b"></div>
</div>
以下是布局的基本样式:
.resizer {
/* 所有 resizer 都绝对位于元素内部 */
position: absolute;
}
/* 放在右边 */
.resizer-r {
top: 0;
right: 0;
width: 5px;
height: 100%;
cursor: col-resize;
}
/* 放置在底部 */
.resizer-b {
left: 0;
bottom: 0;
width: 100%;
height: 5px;
cursor: row-resize;
}
为了使元素可调整大小,我们将处理三个事件:
- 在
resizer
上使用mousedown
— 跟踪鼠标的当前位置和原始元素的尺寸 - 在
document
上使用mousemove
— 计算鼠标移动了多远,并调整元素的尺寸 - 在
document
上使用mouseupon
— 删除document
上的事件处理程序
const ele = document.getElementById('resizeMe')
// 鼠标当前位置
let x = 0
let y = 0
// 元素的维度
let w = 0
let h = 0
// 处理鼠标按下事件
// 当用户拖动 resizer 时触发
const mouseDownHandler = function (e) {
// 获取当前鼠标位置
x = e.clientX
y = e.clientY
// 计算元素的维度
const styles = window.getComputedStyle(ele)
w = parseInt(styles.width, 10)
h = parseInt(styles.height, 10)
// 将监听器附加到 document
document.addEventListener('mousemove', mouseMoveHandler)
document.addEventListener('mouseup', mouseUpHandler)
}
const mouseMoveHandler = function (e) {
// 鼠标移动了多远
const dx = e.clientX - x
const dy = e.clientY - y
// 调整元素的尺寸
ele.style.width = `${w + dx}px`
ele.style.height = `${h + dy}px`
}
const mouseUpHandler = function () {
// 移除 mousemove 和 mouseup 的处理程序
document.removeEventListener('mousemove', mouseMoveHandler)
document.removeEventListener('mouseup', mouseUpHandler)
}
所有的事件处理程序都准备好了。最后,我们将 mousedown
事件处理程序附加到所有调整器:
const resizers = ele.querySelectorAll('.resizer')
;[].forEach.call(resizers, (resizer) => {
resizer.addEventListener('mousedown', mouseDownHandler)
})