SOURCE

console 命令行工具 X clear

                    
>
console
class DraggableWindow {
    constructor(el, elDragHandler) {
        this.el = el;
        this.elDragHandler = elDragHandler;
    
        this.onDragStart = this.onDragStart.bind(this);
        this.onDragMove = this.onDragMove.bind(this);
        this.onDragEnd = this.onDragEnd.bind(this);

        this.startOffsetX = 0;
        this.startOffsetY = 0;
        this.dragging = false;
        this.bindEvents();

    }

    bindEvents() {
        document.body.addEventListener('mousedown', this.onDragStart);
    }

    onDragStart(evt) {
        const { target, offsetX, offsetY, pageX, pageY } = evt;
        if (!this.elDragHandler.contains(target)) {
            return
        }
        this.dragging = true;
        this.startOffsetX = offsetX;
        this.startOffsetY = offsetY;
        window.addEventListener('mousemove', this.onDragMove);
        window.addEventListener('mouseup', this.onDragEnd);
    }

    onDragMove(evt) {
        const { target, pageX, pageY } = evt;
        if (!this.dragging) {
            return;
        }
        this.el.style.left = `${pageX - this.startOffsetX}px`;
        this.el.style.top = `${pageY - this.startOffsetY}px`
    }

    onDragEnd() {
        this.dragging = false;
    }

}

new DraggableWindow(document.querySelector('.modal'), document.querySelector('.modal-header'))
<div class="modal" data-draggable>
	<div class="modal-header">标题</div>
	<div class="modal-content"></div>
</div>
html,
body {
    padding: 0;
    margin: 0;
}

* {
    box-sizing: border-box;
}

.modal {
    left: 50%;
    top: 50%;
    position: absolute;
    width: 500px;
    height: 400px;
    background-color: #888;
    display: flex;
    flex-direction: column;
    border: 1px solid #888;
}

.modal-header {
    height: 40px;
    line-height: 40px;
    padding-left: 12px;
    user-select: none;
    cursor: pointer;
}

.modal-content {
    background-color: #fefefe;
    flex: 1;
}