# js原生实现拖拽

# 思路:

  1. 元素需要脱离文档流。设置为 position : absolute
  2. 鼠标点击时,获取点击的位置距离元素的左边和顶边的偏移量。
  3. 鼠标移动,是在父元素中移动,一般是 html,即 document.documentElement。注意不是在元素中移动
    1. 获取 鼠标点击位置的客户端坐标值(clientX,clientY),根据偏移量计算出元素 style 属性的 left 和 top 值。
    2. 鼠标放开清除移动事件。
  4. 边界的处理。
    1. 上边界,左边界。判断 offsetTop 或者 offsetLeft 值 <= 0。相应地改变元素的位置。
    2. 下边界,右边界。
      1. 下边界。 offsetTop >= 元素可移动的区域 height - 元素自身的高度。
      2. 右边界。 offsetLeft >= 元素可移动的区域 width - 元素自身的宽度。

# 注意点

  1. 获取窗口的宽高用 document.documentElement.clientWidth || clientHeight。用 html 元素的 offsetHeight 和 offsetWidth 偏移量的话,会是 0,查看 dom 节点会发现其未被撑开。

# 代码实现

    class Drag {
    constructor(ele) {
        this.ele = ele;
        this.ele.onmousedown = this.onmousedown.bind(this);
    }

    onmousedown(e) {
        e = e || window.event;
        this.offsetX = e.clientX - this.ele.offsetLeft;
        this.offsetY = e.clientY - this.ele.offsetTop;
        document.documentElement.onmousemove = this.onmousemove.bind(this);
        document.documentElement.onmouseup = this.onmouseup.bind(this);
        // mousemove 事件只有在元素内部移动时才会触发
    }

    onmousemove(e) {
        e = e || window.event;
        let { offsetWidth, offsetHeight } = this.ele;
        let { clientX, clientY } = e;
        let curX = clientX - this.offsetX, curY = clientY - this.offsetY;

        if (curX <= 0) {
            curX = 0;
        } else if (curX > document.documentElement.clientWidth - offsetWidth) {
            curX = document.documentElement.clientWidth - offsetWidth;
        }

        if (curY <= 0) {
            curY = 0;
        } else if (curY > document.documentElement.clientHeight - offsetHeight) {
            curY = document.documentElement.clientHeight - offsetHeight;
        }


        this.ele.style.left = curX + 'px';
        this.ele.style.top = curY + 'px';

    }

    onmouseup() {
        document.documentElement.onmousemove = null;
    }
}