Перетаскиваемое и изменяемое по размеру окно на вашем сайте

Создайте перетаскиваемое и изменяемое по размеру окно, которое выглядит и ощущается как окно в настольной ОС.
Весь код расположен ниже. Давайте вкратце рассмотрим HTML, а затем я объясню, что такое JS.

HTML

<div class="window">
  <div class="resizer corner tl"></div>
  <div class="resizer corner tr"></div>
  <div class="resizer corner bl"></div>
  <div class="resizer corner br"></div>
  <div class="resizer t"></div>
  <div class="resizer b"></div>
  <div class="resizer l"></div>
  <div class="resizer r"></div>

  <div class="body">
    <div class="topbar">
      <div class="btns">
        <div></div>
        <div></div>
        <div></div>
      </div>
    </div>

    <!-- your content here -->
  </div>
</div>
Вход в полноэкранный режим Выход из полноэкранного режима

Здесь у нас есть 4 органайзера по углам и 4 по бокам окна. Мы сможем перетаскивать окно, удерживая его верхнюю панель.

JS

Объявим переменные-селекторы окна и топбара.

const xwindow = document.querySelector(".window")
const topbar = document.querySelector(".topbar")
Вход в полноэкранный режим Выход из полноэкранного режима

Перетаскивание

Мы сможем перетаскивать окно, удерживая кнопку мыши и перемещая его. Слушатель mousemove будет добавлен только при срабатывании mousedown. Поэтому нам также нужен mouseup, чтобы удалить mousemove при отпускании кнопки мыши.
Давайте теперь добавим слушателя mousedown в верхнюю панель и создадим функцию mousedown().

//topbar can be whatever you want to hold while dragging
topbar.addEventListener("mousedown", mousedown)

function mousedown(){
  window.addEventListener("mousemove", mousemove)
  window.addEventListener("mouseup", mouseup)
  function mousemove(){}
  function mouseup(){
    window.removeEventListener("mousemove", mousemove)
    window.removeEventListener("mouseup", mouseup)
  }
}
Вход в полноэкранный режим Выход из полноэкранного режима

Итак, теперь мы хотим, чтобы JS отслеживал положение курсора и перемещал окна при перемещении курсора. Для этого нам понадобится e (или event), которая кроме всего прочего хранит информацию о положении курсора. Передадим его в качестве аргумента функции.

function mousedown(e){
  ...
  function mousemove(e){}
  ...
}
Войти в полноэкранный режим Выход из полноэкранного режима

Чтобы изменить положение окна, мы можем сложить разницу между новым и предыдущим положением курсора и добавить эту разницу к левому и верхнему значениям окна (наше окно абсолютно позиционировано). Получим предыдущие значения координат курсора. До того, как мы переместим курсор, эти значения будут просто текущими значениями.

function mousedown(e){
  ...
  let prevX = e.clientX
  let prevY = e.clientY
  function mousemove(e){}
  ...
}
Вход в полноэкранный режим Выход из полноэкранного режима

Теперь найдем разницу между новым и предыдущим положениями.

...
let prevX = e.clientX
let prevY = e.clientY
function mousemove(e){
  let newX = e.clientX - prevX
  let newY = e.clientY - prevY
}
...
Войти в полноэкранный режим Выход из полноэкранного режима

Метод JavaScript getBoundingClientRect() возвращает объект DOMRect, предоставляющий информацию о размере элемента и его положении относительно области просмотра. С его помощью мы можем получить значения свойств top и left и установить новые значения.

function mousemove(e){
  let newX = e.clientX - prevX
  let newY = e.clientY - prevY
  const rect = xwindow.getBoundingClientRect()
  xwindow.style.left = rect.left + newX + "px"
  xwindow.style.top = rect.top + newY + "px"
  prevX = e.clientX
  prevY = e.clientY
}
Вход в полноэкранный режим Выход из полноэкранного режима

Поздравляем! Теперь мы можем перетаскивать наше окно.

Изменение размеров

Давайте воспользуемся всеми возможностями изменения размеров.

const resizers = document.querySelectorAll(".resizer")
Войти в полноэкранный режим Выход из полноэкранного режима

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

for (let resizer of resizers){
  resizer.addEventListener("mousedown", mousedown)
  function mousedown(e){
    window.addEventListener("mousemove", mousemove)
    window.addEventListener("mouseup", mouseup)
    let prevX = e.clientX
    let prevY = e.clientY
    function mousemove(e){
      const rect = xwindow.getBoundingClientRect()
      prevX = e.clientX
      prevY = e.clientY
    }
    function mouseup(){
      window.removeEventListener("mousemove", mousemove)
      window.removeEventListener("mouseup", mouseup)
    }
  }
}
Вход в полноэкранный режим Выход из полноэкранного режима

Теперь нам нужно сообщить JS, какой именно ресайзер мы держим. Мы можем легко проверить это по их классу. Например, tl означает «top-left». Чтобы проверить, имеет ли текущий ресайзер такой класс, сначала нужно объявить currentResiser и присвоить его e.target (элементу, который мы держим).

...
let prevY = e.clientY
let currentResizer = e.target
...
Вход в полноэкранный режим Выход из полноэкранного режима

Чтобы проверить, есть ли какой-нибудь класс в списке классов ресайзера, мы используем currentResizer.classList.contains("tl") в операторе if. Если да, то нам нужно вычислить новый размер окон. Также, если это верхний, левый или верхне-левый ресайзер, нужно изменить top и left.

...
function mousemove(e){
  const rect = xwindow.getBoundingClientRect()
  if(currentResizer.classList.contains("br")){
    xwindow.style.width = rect.width + (e.clientX - prevX) + "px"
    xwindow.style.height = rect.height + (e.clientY - prevY) + "px"
  }
  else if(currentResizer.classList.contains("bl")){
    xwindow.style.width = rect.width + (prevX - e.clientX) + "px"
    xwindow.style.height = rect.height + (e.clientY - prevY) + "px"
    xwindow.style.left = rect.left + (e.clientX - prevX) + "px"
  }
  else if(currentResizer.classList.contains("tr")){
    xwindow.style.width = rect.width + (e.clientX - prevX) + "px"
    xwindow.style.height = rect.height + (prevY - e.clientY) + "px"
    xwindow.style.top = rect.top + (e.clientY - prevY) + "px"
  }
  else if(currentResizer.classList.contains("tl")){
    xwindow.style.width = rect.width + (prevX - e.clientX) + "px"
    xwindow.style.height = rect.height + (prevY - e.clientY) + "px"
    xwindow.style.top = rect.top + (e.clientY - prevY) + "px"
    xwindow.style.left = rect.left + (e.clientX - prevX) + "px"
  }
  else if(currentResizer.classList.contains("t")){
    xwindow.style.height = rect.height + (prevY - e.clientY) + "px"
    xwindow.style.top = rect.top + (e.clientY - prevY) + "px"
  }
  else if(currentResizer.classList.contains("b")){
    xwindow.style.height = rect.height + (e.clientY - prevY) + "px"
  }
  else if(currentResizer.classList.contains("l")){
    xwindow.style.width = rect.width + (prevX - e.clientX) + "px"
    xwindow.style.left = rect.left + (e.clientX - prevX) + "px"
  }
  else if(currentResizer.classList.contains("r")){
    xwindow.style.width = rect.width + (e.clientX - prevX) + "px"
  }
  prevX = e.clientX
  prevY = e.clientY
}
...
Вход в полноэкранный режим Выйти из полноэкранного режима

Вуаля! Теперь мы также можем изменять размер.

Код

HTML

<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <link rel="stylesheet" href="style.css">
  <script defer src="index.js"></script>
</head>
<body>

  <div class="window">
    <div class="resizer corner tl"></div>
    <div class="resizer corner tr"></div>
    <div class="resizer corner bl"></div>
    <div class="resizer corner br"></div>
    <div class="resizer t"></div>
    <div class="resizer b"></div>
    <div class="resizer l"></div>
    <div class="resizer r"></div>

    <div class="body">
      <div class="topbar">
        <div class="btns">
          <div></div>
          <div></div>
          <div></div>
        </div>
      </div>

      <!-- your content here -->
    </div>
  </div>

</body>
</html>
Вход в полноэкранный режим Выход из полноэкранного режима

SCSS

*{
  margin: 0;
  box-sizing: border-box;
}


.window{
  width: 600px;
  height: 400px;
  min-width: 300px;
  min-height: 200px;
  position: absolute;

  .resizer{
    position: absolute;
    z-index: 1;
    width: 22px;
    height: 22px;
    background: #41a94c80; //delete
    &.corner{
      z-index: 2;
      &.tl{ cursor: nw-resize; top: -5px; left: -5px; }
      &.tr{ cursor: ne-resize; top: -5px; right: -5px; }
      &.bl{ cursor: sw-resize; bottom: -5px; left: -5px; }
      &.br{ cursor: se-resize; bottom: -5px; right: -5px; }
    }
    &.t, &.b{
      width: 100%;
      height: 14px;
    }
    &.l, &.r{
      width: 14px;
      height: 100%;
    }
    &.t{ cursor: n-resize; top: -5px; }
    &.b{ cursor: s-resize; bottom: -5px; }
    &.l{ cursor: w-resize; left: -5px; }
    &.r{ cursor: e-resize; right: -5px; }
  }

  .body{
    border-radius: 15px;
    overflow: hidden;
    height: 100%;
    background: #f4f4f4;
    .topbar{
      width: 100%;
      height: 60px;
      background: #8c8c8c;
      display: flex;
      align-items: center;
      padding: 0 30px;
      .btns{
        display: flex;
        gap: 9px;
        div{
          height: 14px;
          width: 14px;
          border-radius: 50%;
          &:nth-child(1){ background:#FF5F58; }
          &:nth-child(2){ background:#FFBE2F; }
          &:nth-child(3){ background:#2AC940; }
        }
      }
    }
  }

}
Войти в полноэкранный режим Выход из полноэкранного режима

JS

const xwindow = document.querySelector(".window")

const topbar = document.querySelector(".topbar")
topbar.addEventListener("mousedown", mousedown)

function mousedown(e){
  window.addEventListener("mousemove", mousemove)
  window.addEventListener("mouseup", mouseup)
  let prevX = e.clientX
  let prevY = e.clientY
  function mousemove(e){
    let newX = e.clientX - prevX
    let newY = e.clientY - prevY
    const rect = xwindow.getBoundingClientRect()
    xwindow.style.left = rect.left + newX + "px"
    xwindow.style.top = rect.top + newY + "px"
    prevX = e.clientX
    prevY = e.clientY
  }
  function mouseup(){
    window.removeEventListener("mousemove", mousemove)
    window.removeEventListener("mouseup", mouseup)
  }
}



const resizers = document.querySelectorAll(".resizer")

for (let resizer of resizers){
  resizer.addEventListener("mousedown", mousedown)
  function mousedown(e){
    let currentResizer = e.target
    let prevX = e.clientX
    let prevY = e.clientY
    window.addEventListener("mousemove", mousemove)
    window.addEventListener("mouseup", mouseup)
    function mousemove(e){
      const rect = xwindow.getBoundingClientRect()
      if(currentResizer.classList.contains("br")){
        xwindow.style.width = rect.width + (e.clientX - prevX) + "px"
        xwindow.style.height = rect.height + (e.clientY - prevY) + "px"
      }
      else if(currentResizer.classList.contains("bl")){
        xwindow.style.width = rect.width + (prevX - e.clientX) + "px"
        xwindow.style.height = rect.height + (e.clientY - prevY) + "px"
        xwindow.style.left = rect.left + (e.clientX - prevX) + "px"
      }
      else if(currentResizer.classList.contains("tr")){
        xwindow.style.width = rect.width + (e.clientX - prevX) + "px"
        xwindow.style.height = rect.height + (prevY - e.clientY) + "px"
        xwindow.style.top = rect.top + (e.clientY - prevY) + "px"
      }
      else if(currentResizer.classList.contains("tl")){
        xwindow.style.width = rect.width + (prevX - e.clientX) + "px"
        xwindow.style.height = rect.height + (prevY - e.clientY) + "px"
        xwindow.style.top = rect.top + (e.clientY - prevY) + "px"
        xwindow.style.left = rect.left + (e.clientX - prevX) + "px"
      }
      else if(currentResizer.classList.contains("t")){
        xwindow.style.height = rect.height + (prevY - e.clientY) + "px"
        xwindow.style.top = rect.top + (e.clientY - prevY) + "px"
      }
      else if(currentResizer.classList.contains("b")){
        xwindow.style.height = rect.height + (e.clientY - prevY) + "px"
      }
      else if(currentResizer.classList.contains("l")){
        xwindow.style.width = rect.width + (prevX - e.clientX) + "px"
        xwindow.style.left = rect.left + (e.clientX - prevX) + "px"
      }
      else if(currentResizer.classList.contains("r")){
        xwindow.style.width = rect.width + (e.clientX - prevX) + "px"
      }
      prevX = e.clientX
      prevY = e.clientY
    }
    function mouseup(){
      window.removeEventListener("mousemove", mousemove)
      window.removeEventListener("mouseup", mouseup)
    }
  }
}
Войти в полноэкранный режим Выход из полноэкранного режима

Оцените статью
devanswers.ru
Добавить комментарий