首页 > 解决方案 > 无法在嵌套的 shadowdom 中使 div/元素可移动

问题描述

我不能让我的 div 可移动。它是一个自定义元素,由事件监听器创建。这两个自定义元素都有自己的影子。

树形结构 树状结构

第一个自定义元素是<web-desktop>/WebDesktop.js 第二个元素是<app-window>/AppWindow.js

<app-window>在我单击事件侦听器后创建。现在我试图通过单击按钮创建该“窗口”(div)后移动。

但是,我这样做了几个小时都没有成功。

我包括了这两个部分,我坚信问题出在 AppWindow 内。

AppWindow 自定义元素

const template = document.createElement('template')
template.innerHTML = `
<style>
#mydiv {
  position: absolute;
  z-index: 9;
  background-color: #f1f1f1;
  border: 1px solid #d3d3d3;
  text-align: center;
}
#mydivheader {
  padding: 10px;
  cursor: move;
  z-index: 10;
  background-color: #2196F3;
  color: #fff;
}
</style>
<div id="mydiv">
  <div id="mydivheader">Click here to move</div>
  <p>Move</p>
  <p>this</p>
  <p>DIV</p>
</div>
`

class AppWindow extends window.HTMLElement {
  constructor() {
    super()

    this.attachShadow({ mode: 'open' })
    this.shadowRoot.appendChild(template.content.cloneNode(true))
    this.appWindowHeader = this.shadowRoot.querySelector('#mydivheader')
    this.appWindow = this.shadowRoot.querySelector('#mydiv')

    this.prevX = undefined
    this.prevY = undefined
    this.newX = undefined
    this.newY = undefined
  }

  static get observedAttributes() {
    return []
  }

  attributesChangedCallback(name, oldValue, newValue) {
  }

  connectedCallback() {
    this.appWindow.addEventListener('mousedown', this.mousedown)
  }

  mousedown(event) {
    window.addEventListener('mousemove', this.mousemove)
    window.addEventListener('mouseup', this.mouseup)
    this.prevX = event.clientX
    this.prevY = event.clientY
  }

  mousemove(event) {
    this.newX = event.clientX
    this.newY = event.clientY
    const rect = this.appWindow.getBoundingClientRect()

    this.appWindow.style.left = rect.left - this.newX + 'px'
    this.appWindow.style.right = rect.top - this.newY + 'px'

    this.prevX = event.clientX
    this.prevY = event.clientY
  }

  mouseup() {

  }

}

window.customElements.define('app-window', AppWindow)

export { AppWindow }

Web桌面自定义元素

import { AppWindow } from './AppWindow.js'
const template = document.createElement('template')
template.innerHTML = `
<style>
.resizer {
  position: absolute;
  width: 10px;
  height: 10px;
  border-radius: 5px;
  background-color: black;
  z-index: 2;
}
#appImg1 {
  cursor:pointer;
}
#menuDiv {
  background-color: rgb(23, 23, 23);
  position: fixed;
  bottom: 0;
  width: 100%;
  padding: 0px;
  margin: 0px;
}
#menuDiv img {
  margin-left: 25px;
}
hr {
  border: 1px solid black;
  border-radius: 0px;
  margin:0;
  margin-bottom:5px;
}
</style>

<div id="webDesktopDiv">

  <div id="menuDiv">
  <hr>
  <img src="../image/icon.png" id="appImg1">
  </div>

</div>
`
class WebDesktop extends window.HTMLElement {
  constructor() {
    super()

    this.attachShadow({ mode: 'open' })
    this.shadowRoot.appendChild(template.content.cloneNode(true))

    this.menuDiv = this.shadowRoot.querySelector('#menuDiv')
    this.webDesktopDiv = this.shadowRoot.querySelector('#webDesktopDiv')
    this.appImg1 = this.shadowRoot.querySelector('#appImg1')

  }

  static get observedAttributes() {
    return []
  }

  attributesChangedCallback(name, oldValue, newValue) {
  }

  connectedCallback() {
    this.appImg1.addEventListener('click', event => {
      this.createWindow()
    })
  }

  createWindow() {
    let appWindow = document.createElement('app-window')
    appWindow.classList = 'item'
    appWindow.setAttribute('draggable', 'true')
    this.webDesktopDiv.appendChild(appWindow)
  }
}

window.customElements.define('web-desktop', WebDesktop)
export { WebDesktop }

标签: javascriptweb-componentshadow-domcustom-element

解决方案


在 上<app-window>,您应该使用dragstart事件处理程序并记录您在属性中单击的位置DragEvent.dataTransfer

应用程序窗口.js

const template = `
<style>
:host {
    position: absolute
}
#mydiv {
    z-index: 9;
    background-color: #f1f1f1;
    border: 1px solid #d3d3d3;
    text-align: center;
}
#mydivheader {
    padding: 10px;
    cursor: move;
    z-index: 10;
    background-color: #2196F3;
    color: #fff;
}
</style>
<div id="mydiv">
  <div id="mydivheader">Click here to move</div>
  <p>Move</p>
  <p>this</p>
  <p>DIV</p>
</div>
`
var count = 0 
class AppWindow extends window.HTMLElement {
    constructor() {
        super()
        this.attachShadow({ mode: 'open' }).innerHTML = template
    }

    connectedCallback() {
        this.setAttribute( 'draggable', 'true' )
        this.id = count++
        this.ondragstart = ev => ev.dataTransfer.setData( 'text', JSON.stringify( {
            id: ev.target.id,
            x: ev.clientX,
            y: ev.clientY
        } ) )
    }
}

window.customElements.define('app-window', AppWindow)

export { AppWindow }

<web-desktop>容器上,你应该阻止dragover事件的默认行为,然后定义一个事件处理程序来设置根据上下点击差异计算drop的新位置:<app-window>

网页桌面.js

import { AppWindow } from './AppWindow.js'
const template = `
<style>
:host {
    height: 100% ;
    display: block ;
}

button {
  position: fixed;
  bottom: 10px; left: 10px;
}
</style>

  <button>Add</buton>
`
var count = 0

class WebDesktop extends window.HTMLElement {
  constructor() {
    super()
    this.attachShadow( { mode: 'open' } ).innerHTML = template
  }

  connectedCallback() {
    this.shadowRoot.querySelector( 'button' ).onclick = () => this.shadowRoot.appendChild( new AppWindow )
    this.ondragover = ev => ev.preventDefault()
    this.ondrop = ev => {
        let origin = JSON.parse( ev.dataTransfer.getData( 'text' ) )
        console.log( origin )
        let app = this.shadowRoot.getElementById( origin.id )
        let childPos = app.getBoundingClientRect()
        app.style.left = childPos.left + ( ev.clientX - origin.x ) + 'px'
        app.style.top = childPos.top + ( ev.clientY - origin.y ) + 'px'
    } 
  }
}

window.customElements.define('web-desktop', WebDesktop)

推荐阅读