Как сделать HTML-элемент изменяемым размером с помощью чистого Javascript?

Мне было интересно, как мы можем сделать элемент HTML, такой как

или

, изменяемый размер элемента тега при нажатии, используя чистый JavaScript, а не библиотеку jQuery или любую другую библиотеку. .

57
задан Brian Tompsett - 汤莱恩 21 August 2019 в 18:54
поделиться

1 ответ

Существуют очень хорошие примеры здесь, чтобы начать пробовать, но все они основаны на добавлении некоторого дополнительного или внешнего элемента как "отделение" как опорный элемент, чтобы перетащить его и вычислить новые размеры или положение исходного элемента.

Вот пример, который не использует дополнительных элементов. Мы могли добавить границы, дополнив или поле, не влияя на его операцию. В этом примере мы не добавили цвет, ни любую визуальную ссылку на границы, ни на правый нижний угол как подсказка, где можно увеличить или уменьшить размеры, но использование курсора вокруг элементов изменяемого размера, подсказки появляются!

let resizerForCenter = new Resizer('center')  
resizerForCenter.initResizer()

Посмотрите его в действии с CodeSandbox:

В этом примере мы используем ES6 и модуль, который экспортирует класс под названием Resizer. Пример стоит тысячу слов:

Edit vigorous-chaum-cemm5

Или с фрагментом кода:

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>
0
ответ дан 24 November 2019 в 19:14
поделиться
Другие вопросы по тегам:

Похожие вопросы: