css 我怎样才能让div不从紫色div中出来呢?

wsxa1bj1  于 2023-06-25  发布在  其他
关注(0)|答案(1)|浏览(126)
let isSelecting = false;
let selectionStartX, selectionStartY, selectionEndX, selectionEndY;
let selectionRectangle;
let draggedElements = [];
const widgets = document.querySelectorAll('.widgets');
const widgetContainer = document.getElementById('widget-container');

document.addEventListener('mousedown', (event) => {
  const header = event.target.closest('.widget-header');
  if (header) {
    const widget = header.parentElement;
    // If the clicked widget is not selected
    if (!widget.classList.contains('selected')) {
      // deselect all widgets 
      widgets.forEach((widget) => {
        widget.classList.remove('selected');
      });
      // and only drag the clicked one
      draggedElements = [widget];
    } else {
      // otherwise drag the selected 
      draggedElements = Array.from(widgets).filter((widget) => widget.classList.contains('selected'));
    }

    draggedElements.forEach((widget) => {
      const shiftX = event.clientX - widget.getBoundingClientRect().left;
      const shiftY = event.clientY - widget.getBoundingClientRect().top;

      function moveElement(event) {
        const x = event.clientX - shiftX;
        const y = event.clientY - shiftY;

        widget.style.left = x + 'px';
        widget.style.top = y + 'px';
      }

      function stopMoving() {
        document.removeEventListener('mousemove', moveElement);
        document.removeEventListener('mouseup', stopMoving);
      }

      document.addEventListener('mousemove', moveElement);
      document.addEventListener('mouseup', stopMoving);
    });

    return;
  }

  const isWidgetClicked = Array.from(widgets).some((widget) => {
    const widgetRect = widget.getBoundingClientRect();
    return (
      event.clientX >= widgetRect.left &&
      event.clientX <= widgetRect.right &&
      event.clientY >= widgetRect.top &&
      event.clientY <= widgetRect.bottom
    );
  });

  if (!isWidgetClicked && event.target !== selectionRectangle) { // Check if the target is not the selection rectangle
    isSelecting = true;
    selectionStartX = event.clientX;
    selectionStartY = event.clientY;
    selectionRectangle = document.createElement('div');
    selectionRectangle.id = 'selection-rectangle';
    selectionRectangle.style.position = 'absolute';
    selectionRectangle.style.border = '2px dashed blue';
    selectionRectangle.style.pointerEvents = 'none';
    selectionRectangle.style.display = 'none';
    document.body.appendChild(selectionRectangle);

    // Remove selected class from widgets
    widgets.forEach((widget) => {
      widget.classList.remove('selected');
    });
  }
});

document.addEventListener('mousemove', (event) => {
  if (isSelecting) {
    selectionEndX = event.clientX;
    selectionEndY = event.clientY;

    let width = Math.abs(selectionEndX - selectionStartX);
    let height = Math.abs(selectionEndY - selectionStartY);

    selectionRectangle.style.width = width + 'px';
    selectionRectangle.style.height = height + 'px';
    selectionRectangle.style.left = Math.min(selectionEndX, selectionStartX) + 'px';
    selectionRectangle.style.top = Math.min(selectionEndY, selectionStartY) + 'px';
    selectionRectangle.style.display = 'block';

    widgets.forEach((widget) => {
      const widgetRect = widget.getBoundingClientRect();
      const isIntersecting = isRectangleIntersecting(widgetRect, {
        x: Math.min(selectionStartX, selectionEndX),
        y: Math.min(selectionStartY, selectionEndY),
        width,
        height,
      });
      if (isIntersecting) {
        widget.classList.add('selected');
      } else {
        widget.classList.remove('selected');
      }
    });
  }
});

document.addEventListener('mouseup', () => {
  if (isSelecting) {
    isSelecting = false;
    selectionRectangle.remove();
  }
});

function isRectangleIntersecting(rect1, rect2) {
  return (
    rect1.left >= rect2.x &&
    rect1.top >= rect2.y &&
    rect1.right <= rect2.x + rect2.width &&
    rect1.bottom <= rect2.y + rect2.height
  );
}
#selection-rectangle {
  position: absolute;
  border: 2px dashed blue;
  pointer-events: none;
  display: none;
  z-index: 9999999;
}

.widgets.selected {
  outline-color: blue;
  outline-width: 2px;
  outline-style: dashed;
}

.widgets {
  position: absolute;
  z-index: 9;
  background-color: #000000;
  color: white;
  font-size: 25px;
  font-family: Arial, Helvetica, sans-serif;
  border: 2px solid #212128;
  text-align: center;
  width: 500px;
  height: 200px;
  min-width: 166px;
  min-height: 66px;
  overflow: hidden;
  resize: both;
  image-resolution: none;
  border-radius: 10px;
}

.widget-header {
  padding: 10px;
  cursor: move;
  z-index: 10;
  background-color: #040c14;
  outline-color: white;
  outline-width: 2px;
  outline-style: solid;
}

#purple-div {
  width: 1000px;
  height: 700px;
  background-color: purple;
  position: absolute;
}
<div id="widget1" class="widgets" style="left: 50px; top: 50px;">
    <div id="widget1header" class="widget-header"></div>
  </div>

  <div id="widget2" class="widgets" style="left: 150px; top: 150px;">
    <div id="widget2header" class="widget-header"></div>
  </div>

  <div id="widget3" class="widgets" style="left: 250px; top: 250px;">
    <div id="widget3header" class="widget-header"></div>
  </div>

  <div id="purple-div"></div>

我想小部件被限制的紫色div,我不知道如何做到这一点。鼠标还必须始终从开始拖动的位置拖动,这意味着如果鼠标碰到了边框,鼠标必须回到它拖动小部件的位置才能移动(当鼠标向下时,这意味着拖动)。

7xllpg7q

7xllpg7q1#

继续我的回答:是否有针对在多个事件侦听器上执行的逻辑的设计模式

const container = document.querySelector('.container');

const draggables = document.querySelectorAll('.draggable');

draggables.forEach(elem => {
  makeDraggableResizable(elem);
  elem.addEventListener('mousedown', () => {
     const maxZ = Math.max(...[...draggables].map(elem => parseInt(getComputedStyle(elem)['z-index']) || 0));
     elem.style['z-index'] = maxZ + 1;
  });
});

function makeDraggableResizable(draggable){

  const move = (x, y) => {

    x = state.fromX + (x - state.startX);
    y = state.fromY + (y - state.startY);

    // don't allow moving outside the container
    if (x < 0) x = 0;
    else if (x + draggable.offsetWidth > container.offsetWidth) x = container.offsetWidth - draggable.offsetWidth;

    if (y < 0) y = 0;
    else if (y + draggable.offsetHeight > container.offsetHeight) y = container.offsetHeight - draggable.offsetHeight;

    draggable.style.left = x + 'px';
    draggable.style.top = y + 'px';
  };

  const resize = (x, y) => {

    x = state.fromWidth + (x - state.startX);
    y = state.fromHeight + (y - state.startY);

    // don't allow moving outside the container
    if (state.fromX + x > container.offsetWidth) x = container.offsetWidth - state.fromX;

    if (state.fromY + y > container.offsetHeight ) y = container.offsetHeight - state.fromY;

    draggable.style.width = x + 'px';
    draggable.style.height = y + 'px';
  };

  const listen = (op = 'add') => 
    Object.entries(listeners).slice(1)
      .forEach(([name, listener]) => document[op + 'EventListener'](name, listener));

  const state = new Proxy({}, {
    set(state, prop, val){
      const out = Reflect.set(...arguments);
      const ops = {
        startY: () => {
          listen();
          const style = getComputedStyle(draggable);
          [state.fromX, state.fromY] = [parseInt(style.left), parseInt(style.top)];
          [state.fromWidth, state.fromHeight] = [parseInt(style.width), parseInt(style.height)];
        },
        dragY: () => state.action(state.dragX, state.dragY),
        stopY: () => listen('remove') + state.action(state.stopX, state.stopY),
      };
      // use a resolved Promise to postpone the move as a microtask so
      // the order of state mutation isn't important
      ops[prop] && Promise.resolve().then(ops[prop]);
      return out;
    }
  });

  const listeners = {
    mousedown: e => Object.assign(state, {startX: e.pageX, startY: e.pageY}),
    // here we first provide dragY to check that the order of props is not important
    mousemove: e => Object.assign(state, {dragY: e.pageY, dragX: e.pageX}),
    mouseup: e => Object.assign(state, {stopX: e.pageX, stopY: e.pageY}),
  };

  for(const [name, action] of Object.entries({move, resize})){
    draggable.querySelector(`.${name}`).addEventListener('mousedown', e => {
      state.action = action;
      listeners.mousedown(e);
    }); 
  }

}
html,body{
  height:100%;
  margin:0;
  padding:0;
}
*{
  box-sizing: border-box;
}

.draggable{
  position: absolute;
  padding:45px 15px 15px 15px;
  border-radius:4px;
  background:#ddd;
  user-select: none;
  left: 15px;
  top: 15px;
  min-width:200px;
}
.draggable>.move{
  line-height: 30px;
  padding: 0 15px;
  background:#bbb;
  border-bottom: 1px solid #777;
  cursor:move;
  position:absolute;
  left:0;
  top:0;
  height:30px;
  width:100%;
  border-radius: 4px 4px 0;
}
.draggable>.resize{
  cursor:nw-resize;
  position:absolute;
  right:0;
  bottom:0;
  height:16px;
  width:16px;
  border-radius: 0 0 4px 0;
  background: linear-gradient(to left top, #777 50%, transparent 50%)
}
.container{
  left:15px;
  top:15px;
  background: #111;
  border-radius:4px;
  width:calc(100% - 30px);
  height:calc(100% - 30px);
  position: relative;
}
<div class="container">
  <div class="draggable"><div class="move">draggable handle</div>Non-draggable content<div class="resize"></div></div>
    <div class="draggable" style="left:230px;"><div class="move">draggable handle</div>Non-draggable content<div class="resize"></div></div>
</div>

相关问题