Мне было интересно, как мы можем сделать элемент HTML, такой как
, изменяемый размер элемента тега при нажатии, используя чистый JavaScript, а не библиотеку jQuery или любую другую библиотеку. .
Существуют очень хорошие примеры здесь, чтобы начать пробовать, но все они основаны на добавлении некоторого дополнительного или внешнего элемента как "отделение" как опорный элемент, чтобы перетащить его и вычислить новые размеры или положение исходного элемента.
Вот пример, который не использует дополнительных элементов. Мы могли добавить границы, дополнив или поле, не влияя на его операцию. В этом примере мы не добавили цвет, ни любую визуальную ссылку на границы, ни на правый нижний угол как подсказка, где можно увеличить или уменьшить размеры, но использование курсора вокруг элементов изменяемого размера, подсказки появляются!
let resizerForCenter = new Resizer('center')
resizerForCenter.initResizer()
Посмотрите его в действии с CodeSandbox:
В этом примере мы используем ES6 и модуль, который экспортирует класс под названием Resizer. Пример стоит тысячу слов:
Или с фрагментом кода:
const html = document.querySelector('html')
class Resizer {
constructor(elemId) {
this._elem = document.getElementById(elemId)
/**
* Stored binded context handlers for method passed to eventListeners!
*
* See: https://stackoverflow.com/questions/9720927/removing-event-listeners-as-class-prototype-functions
*/
this._checkBorderHandler = this._checkBorder.bind(this)
this._doResizeHandler = this._doResize.bind(this)
this._initResizerHandler = this.initResizer.bind(this)
this._onResizeHandler = this._onResize.bind(this)
}
initResizer() {
this.stopResizer()
this._beginResizer()
}
_beginResizer() {
this._elem.addEventListener('mousemove', this._checkBorderHandler, false)
}
stopResizer() {
html.style.cursor = 'default'
this._elem.style.cursor = 'default'
window.removeEventListener('mousemove', this._doResizeHandler, false)
window.removeEventListener('mouseup', this._initResizerHandler, false)
this._elem.removeEventListener('mousedown', this._onResizeHandler, false)
this._elem.removeEventListener('mousemove', this._checkBorderHandler, false)
}
_doResize(e) {
let elem = this._elem
let boxSizing = getComputedStyle(elem).boxSizing
let borderRight = 0
let borderLeft = 0
let borderTop = 0
let borderBottom = 0
let paddingRight = 0
let paddingLeft = 0
let paddingTop = 0
let paddingBottom = 0
switch (boxSizing) {
case 'content-box':
paddingRight = parseInt(getComputedStyle(elem).paddingRight)
paddingLeft = parseInt(getComputedStyle(elem).paddingLeft)
paddingTop = parseInt(getComputedStyle(elem).paddingTop)
paddingBottom = parseInt(getComputedStyle(elem).paddingBottom)
break
case 'border-box':
borderRight = parseInt(getComputedStyle(elem).borderRight)
borderLeft = parseInt(getComputedStyle(elem).borderLeft)
borderTop = parseInt(getComputedStyle(elem).borderTop)
borderBottom = parseInt(getComputedStyle(elem).borderBottom)
break
default: break
}
let horizontalAdjustment = (paddingRight + paddingLeft) - (borderRight + borderLeft)
let verticalAdjustment = (paddingTop + paddingBottom) - (borderTop + borderBottom)
let newWidth = elem.clientWidth + e.movementX - horizontalAdjustment + 'px'
let newHeight = elem.clientHeight + e.movementY - verticalAdjustment + 'px'
let cursorType = getComputedStyle(elem).cursor
switch (cursorType) {
case 'all-scroll':
elem.style.width = newWidth
elem.style.height = newHeight
break
case 'col-resize':
elem.style.width = newWidth
break
case 'row-resize':
elem.style.height = newHeight
break
default: break
}
}
_onResize(e) {
// On resizing state!
let elem = e.target
let newCursorType = undefined
let cursorType = getComputedStyle(elem).cursor
switch (cursorType) {
case 'nwse-resize':
newCursorType = 'all-scroll'
break
case 'ew-resize':
newCursorType = 'col-resize'
break
case 'ns-resize':
newCursorType = 'row-resize'
break
default: break
}
html.style.cursor = newCursorType // Avoid cursor's flickering
elem.style.cursor = newCursorType
// Remove what is not necessary, and could have side effects!
elem.removeEventListener('mousemove', this._checkBorderHandler, false);
// Events on resizing state
/**
* We do not apply the mousemove event on the elem to resize it, but to the window to prevent the mousemove from slippe out of the elem to resize. This work bc we calculate things based on the mouse position
*/
window.addEventListener('mousemove', this._doResizeHandler, false);
window.addEventListener('mouseup', this._initResizerHandler, false);
}
_checkBorder(e) {
const elem = e.target
const borderSensitivity = 5
const coor = getCoordenatesCursor(e)
const onRightBorder = ((coor.x + borderSensitivity) > elem.scrollWidth)
const onBottomBorder = ((coor.y + borderSensitivity) > elem.scrollHeight)
const onBottomRightCorner = (onRightBorder && onBottomBorder)
if (onBottomRightCorner) {
elem.style.cursor = 'nwse-resize'
} else if (onRightBorder) {
elem.style.cursor = 'ew-resize'
} else if (onBottomBorder) {
elem.style.cursor = 'ns-resize'
} else {
elem.style.cursor = 'auto'
}
if (onRightBorder || onBottomBorder) {
elem.addEventListener('mousedown', this._onResizeHandler, false)
} else {
elem.removeEventListener('mousedown', this._onResizeHandler, false)
}
}
}
function getCoordenatesCursor(e) {
let elem = e.target;
// Get the Viewport-relative coordinates of cursor.
let viewportX = e.clientX
let viewportY = e.clientY
// Viewport-relative position of the target element.
let elemRectangle = elem.getBoundingClientRect()
// The function returns the largest integer less than or equal to a given number.
let x = Math.floor(viewportX - elemRectangle.left) // - elem.scrollWidth
let y = Math.floor(viewportY - elemRectangle.top) // - elem.scrollHeight
return {x, y}
}
let resizerForCenter = new Resizer('center')
resizerForCenter.initResizer()
let resizerForLeft = new Resizer('left')
resizerForLeft.initResizer()
setTimeout(handler, 10000, true); // 10s
function handler() {
resizerForCenter.stopResizer()
}
body {
background-color: white;
}
#wrapper div {
/* box-sizing: border-box; */
position: relative;
float:left;
overflow: hidden;
height: 50px;
width: 50px;
padding: 3px;
}
#left {
background-color: blueviolet;
}
#center {
background-color:lawngreen ;
}
#right {
background: blueviolet;
}
#wrapper {
border: 5px solid hotpink;
display: inline-block;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Resizer v0.0.1</title>
</head>
<body>
<div id="wrapper">
<div id="left">Left</div>
<div id="center">Center</div>
<div id="right">Right</div>
</div>
</body>
</html>