【问题标题】:Problem with binding and unbinding mouse events to custom element将鼠标事件绑定和解除绑定到自定义元素的问题
【发布时间】:2019-12-29 08:31:48
【问题描述】:

我正在尝试将“鼠标移动”功能添加到我的 CustomElement 以使其能够通过鼠标拖动移动,如下所示。 但是它有很多滞后,并且事件在“mouseup”或“mousedown”事件上无法正确附加和分离。 我不知道为什么会发生这种情况,因为它在简单的“div”元素上正常工作。

拖动功能:

//drag-element.js
export default function dragElement(elm) {
  const header = elm.Cardheader;
  header.style.cursor = "all-scroll";
  let [initX, initY] = [0, 0];
  let mousedown = false;

  let mousemoveEventHandler = function(e) {
    if (mousedown) {
      elm.style.top = `${e.clientY - initY}px`;
      elm.style.left = `${e.clientX - initX}px`;
    }
  };

  let mousedownEventHandler = function(e) {
    mousedown = true;
    header.onmousemove = mousemoveEventHandler;
    initX = e.clientX - elm.offsetLeft;
    initY = e.clientY - elm.offsetTop;
  };

  let mouseupEventHandler = function(e) {
    mousedown = false;
    header.onmousemove = null;
  };

  document.addEventListener("mouseup", mouseupEventHandler);

  header.onmousedown = mousedownEventHandler;
}

自定义元素:

//content-card.js
export default class ContentCard extends HTMLElement {
  constructor() {
    super();
    let shadow = this.attachShadow({ mode: "open" });

    let style = document.createElement("style");
    style.textContent = `
            :host {
                position: absolute;
                background-color: #fff;
                width: 50%;
                margin: 20px auto;
                display: block;
                border: 1px solid #eee;
                box-shadow: 1px 1px 4px 1px #444;
                box-sizing: border-box;
            }
            .header {
                background-color: #eee;
                min-height: 20px;
                display: block;
                padding: 15px;
            }
            .body {
                min-height: 150px;
                display: block;
                padding: 15px;
            }
        `;

    this.Cardheader = document.createElement("div");
    this.Cardheader.setAttribute("class", "header");

    this.Cardbody = document.createElement("div");
    this.Cardbody.setAttribute("class", "body");

    this.Cardheader.textContent = this.getAttribute("subject");
    this.Cardbody.innerHTML = this.getAttribute("content");

    shadow.appendChild(this.Cardheader);
    shadow.appendChild(this.Cardbody);
    shadow.appendChild(style);

  }

  static get observedAttributes() {
    return ["subject", "content"];
  }

  get subject() {
    return this.Cardheader.textContent;
  }
  set subject(val) {
    this.Cardheader.textContent = val;
  }

  get content() {
    return this.Cardbody.innerHTML;
  }

  set content(val) {
    this.Cardbody.innerHTML = val;
  }

  connectedCallback() {}

  disconnectedCallback() {}

  attributeChangedCallback(name, oldValue, newValue) {
    if (newValue === oldValue) return;

    switch (name) {
      case "subject":
        this.subjetct = newValue;
        break;
      case "content":
        this.content = newValue;
        break;
      default:
        break;
    }
  }

  adoptedCallback() {}
}

主要的 Javascript:

//index.js
import ContentCard from "./content-card.js";
import ContentCard from "./drag-element.js";


customElements.define("content-card", ContentCard);

let cCard = new ContentCard();

document.body.appendChild(cCard);

dragElement(cCard);
<html>
    <head>
        <script defer type="module" src="./index.js"></script>
    </head>
    <body>
        <content-card subject="subject" content="Content"></content-card>
    </body>
</html>

【问题讨论】:

  • 这条线应该做什么? document.getElementById;
  • 我编辑了代码。只是粘贴代码时出错了。
  • 您可以在浏览器开发工具中使用分析器来记录滞后并查看导致滞后的原因。取消绑定可能不起作用,因为事件是自定义元素的一部分,所以宁可添加一些属性来阻止事件发生。所以如果属性 x 设置为 true - 只做 e.preventDefault().
  • @fubar,他们可以访问它,因为 javascript "Closures"
  • 所以我要问的另一件事是elm.style.top = e.clientY - initY; 不是elm.style.top = (e.clientY - initY) + 'px';,因为该元素不会以其他方式粘在其新位置并且该行没有意义,这是故意的吗?跨度>

标签: javascript html es6-modules mousemove custom-element


【解决方案1】:

感谢@fubar 和@Zydnar,我更改了主机样式并删除了margin: 20 auto 并将event.preventDefault() 添加到mousedown 事件中,延迟减少了很多,并且在单独的浏览器中修复了解除绑定问题。 (但它仍然存在,代码 sn-ps 的问题)但它不会出现在实际页面中。 我对拖动方法进行了一些改进:

1- 我没有设置elm.style.topelm.style.left,而是使用elm.style.transform =translate(${left}px,${top}px); 2-而不是使用element.offsetLeftelement.offsetTop 我使用 let rect = elm.getBoundingClientRect();rect,leftrect.top

//drag-element.js
function dragElement(elm) {
  const header = elm.Cardheader;
  header.style.cursor = "all-scroll";
  let [initX, initY] = [0, 0];
  let mousedown = false;

  let mousemoveEventHandler = function(e) {
    if (mousedown) {
        let top = e.clientY - initY || elm.top;
        let left = e.clientX - initX || elm.left;
        elm.style.transform = `translate(${left}px,${top}px)`;
    }
  };

  let mousedownEventHandler = function(e) {
    e.preventDefault();
    mousedown = true;
    header.onmousemove = mousemoveEventHandler;
    let rect = elm.getBoundingClientRect();
    initX = e.clientX - rect.left;
    initY = e.clientY - rect.top;
  };

  let mouseupEventHandler = function(e) {
    mousedown = false;
    header.onmousemove = null;
  };

  document.addEventListener("mouseup", mouseupEventHandler);

  header.onmousedown = mousedownEventHandler;
}

//content-card.js
class ContentCard extends HTMLElement {
  constructor() {
    super();
    let shadow = this.attachShadow({ mode: "open" });

    let style = document.createElement("style");
    style.textContent = `
            :host {
                position: absolute;
                background-color: #fff;
                backface-visibility: hidden;
                width: 50%;
                display: block;
                border: 1px solid #eee;
                box-shadow: 1px 1px 4px 1px #444;
                box-sizing: border-box;
            }
            .header {
                background-color: #eee;
                min-height: 20px;
                display: block;
                padding: 15px;
            }
            .body {
                min-height: 150px;
                display: block;
                padding: 15px;
            }
        `;

    this.Cardheader = document.createElement("div");
    this.Cardheader.setAttribute("class", "header");

    this.Cardbody = document.createElement("div");
    this.Cardbody.setAttribute("class", "body");

    this.Cardheader.textContent = this.getAttribute("subject");
    this.Cardbody.innerHTML = this.getAttribute("content");

    shadow.appendChild(this.Cardheader);
    shadow.appendChild(this.Cardbody);
    shadow.appendChild(style);

  }

  static get observedAttributes() {
    return ["subject", "content"];
  }

  get subject() {
    return this.Cardheader.textContent;
  }
  set subject(val) {
    this.Cardheader.textContent = val;
  }

  get content() {
    return this.Cardbody.innerHTML;
  }

  set content(val) {
    this.Cardbody.innerHTML = val;
  }

  connectedCallback() {}

  disconnectedCallback() {}

  attributeChangedCallback(name, oldValue, newValue) {
    if (newValue === oldValue) return;

    switch (name) {
      case "subject":
        this.subjetct = newValue;
        break;
      case "content":
        this.content = newValue;
        break;
      default:
        break;
    }
  }

  adoptedCallback() {}
}

customElements.define("content-card", ContentCard);

let cCard = new ContentCard();

document.body.appendChild(cCard);

dragElement(cCard);

【讨论】:

    【解决方案2】:

    好的,所以px 修复了粘贴问题,并且可以通过将标题的填充添加到initY 来抵消开始时的有趣捕捉行为。这是由于标题具有填充和 elm 的偏移量没有考虑到这一点,并且 header 捕捉到鼠标位置,因此它与 15px 捕捉到太多导致鼠标移出标题和删除元素。有人知道这里正确的道具吗?这将回答你的问题,为什么它有点奇怪......

    关于滞后位,您可能需要考虑跳过一些事件。

    //drag-element.js
    function dragElement(elm) {
      const header = elm.Cardheader;
      header.style.cursor = "all-scroll";
      let [initX, initY] = [0, 0];
      let mousedown = false;
    
      let mousemoveEventHandler = function(e) {
        if (mousedown) {
          elm.style.top = `${e.clientY - initY}px`;
          elm.style.left = `${e.clientX - initX}px`;
        }
      };
    
      let mousedownEventHandler = function(e) {
        mousedown = true;
        elm.onmousemove = mousemoveEventHandler;
        initX = e.clientX - elm.offsetLeft;
        initY = e.clientY - elm.offsetTop + 15;
      };
    
      let mouseupEventHandler = function(e) {
        mousedown = false;
        header.onmousemove = null;
      };
    
      document.addEventListener("mouseup", mouseupEventHandler);
    
      header.onmousedown = mousedownEventHandler;
    }
    
    //content-card.js
    class ContentCard extends HTMLElement {
      constructor() {
        super();
        let shadow = this.attachShadow({ mode: "open" });
    
        let style = document.createElement("style");
        style.textContent = `
                :host {
                    position: absolute;
                    background-color: #fff;
                    width: 50%;
                    margin: 20px auto;
                    display: block;
                    border: 1px solid #eee;
                    box-shadow: 1px 1px 4px 1px #444;
                    box-sizing: border-box;
                }
                .header {
                    background-color: #eee;
                    min-height: 20px;
                    display: block;
                    padding: 15px;
                }
                .body {
                    min-height: 150px;
                    display: block;
                    padding: 15px;
                }
            `;
    
        this.Cardheader = document.createElement("div");
        this.Cardheader.setAttribute("class", "header");
    
        this.Cardbody = document.createElement("div");
        this.Cardbody.setAttribute("class", "body");
    
        this.Cardheader.textContent = this.getAttribute("subject");
        this.Cardbody.innerHTML = this.getAttribute("content");
    
        shadow.appendChild(this.Cardheader);
        shadow.appendChild(this.Cardbody);
        shadow.appendChild(style);
    
      }
    
      static get observedAttributes() {
        return ["subject", "content"];
      }
    
      get subject() {
        return this.Cardheader.textContent;
      }
      set subject(val) {
        this.Cardheader.textContent = val;
      }
    
      get content() {
        return this.Cardbody.innerHTML;
      }
    
      set content(val) {
        this.Cardbody.innerHTML = val;
      }
    
      connectedCallback() {}
    
      disconnectedCallback() {}
    
      attributeChangedCallback(name, oldValue, newValue) {
        if (newValue === oldValue) return;
    
        switch (name) {
          case "subject":
            this.subjetct = newValue;
            break;
          case "content":
            this.content = newValue;
            break;
          default:
            break;
        }
      }
    
      adoptedCallback() {}
    }
    
    customElements.define("content-card", ContentCard);
    
    let cCard = new ContentCard();
    
    document.body.appendChild(cCard);
    
    dragElement(cCard);

    【讨论】:

      猜你喜欢
      • 2020-03-22
      • 1970-01-01
      • 1970-01-01
      • 2012-10-18
      • 1970-01-01
      • 1970-01-01
      • 2010-10-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多