拖放一个元素并放下另一个元素

时间:2020-11-09 13:38:07

标签: html drag-and-drop

我正在尝试使用dynamicllay创建的容器和可放置项实现拖放

  1. 单击按钮的可放置部分将动态创建
  2. 将有带有静态文本的元素的无序列表,例如电子邮件字段,电话号码字段,多个选项等。
  3. 我想基于静态文件类型(电子邮件,电话,多项复选框)动态创建这些列表项中的任何一个的
  4. 需要插入新元素,我创建了部分工作的代码,但是以某种方式无法正常工作,我怀疑我需要对dataTransfer对象做些什么。

这是部分有效的,我能够动态创建元素并将其附加到dom,但是在拖动时却无法按我的预期工作。任何帮助将不胜感激。

let draggables = document.querySelectorAll('.draggable');
let containers = document.querySelectorAll('.container');
let mainContainer = document.getElementById('main-container');
let afterElement;
let elementToInsert;
let count = 0;

let addsec = document.getElementById('addsection');

    addsec.addEventListener('click',function(e){
        let container = document.createElement('div');
            container.classList.add('container');
        let section = document.createElement('h1');
            section.innerHTML = `Section ${count++}`;
            container.appendChild(section);
        mainContainer.appendChild(container)
        init();
    })

    draggables.forEach(draggable => {
        draggable.addEventListener('dragstart', (e) => {
            e.stopPropagation();
          
        console.log("drag start",e,draggable);
        if(draggable && draggable.getAttribute('name')){
            let element = draggable.getAttribute('name');
            switch(element){
                case 'text-field':
                    elementToInsert = document.createElement('input');
                    
                    elementToInsert.classList.add('draggable');
                    elementToInsert.setAttribute('draggable',true);
                    elementToInsert.setAttribute('placeholder','Text');
                    elementToInsert.setAttribute('disabled',true);
                    
                    break;
                case 'email-field':
                        elementToInsert = document.createElement('input');
                        
                        elementToInsert.classList.add('draggable');
                        elementToInsert.setAttribute('draggable',true);
                        elementToInsert.setAttribute('placeholder','Email');
                        elementToInsert.setAttribute('disabled',true);
                        break;
                case 'phone-field':
                    elementToInsert = document.createElement('input');
                    
                    elementToInsert.classList.add('draggable');
                    elementToInsert.setAttribute('draggable',true);
                    elementToInsert.setAttribute('placeholder','Phone');
                    elementToInsert.setAttribute('disabled',true);
                    break;
                default:
                    elementToInsert = draggable;
                    break;
            }
        }else{
            elementToInsert = draggable; 
        }

        elementToInsert.addEventListener('dragstart',function(ev){
            ev.dataTransfer.setData('elementid',ev.target.id);
        })
        elementToInsert.setAttribute('id',`field-${Date.now()}`);
        draggable.classList.add('dragging')
        })
    
        draggable.addEventListener('dragend', () => {
            draggable.classList.remove('dragging')
        })
    })

   
    function init(){
        draggables = document.querySelectorAll('.draggable');
        containers = document.querySelectorAll('.container');
        console.log("draggables",draggables,containers);
        
        containers.forEach(container => {
            container.addEventListener('dragover', e => {
                e.preventDefault()
                let data = e.dataTransfer.getData("elementid");
                console.log("eee",data);
                afterElement = getDragAfterElement(container, e.clientY);
                if (afterElement == null) {
                
                container.appendChild(elementToInsert)
                } else {
                container.insertBefore(elementToInsert, afterElement)
                }
            })
            container.addEventListener('drop', e => {
                e.preventDefault()
                let data = e.dataTransfer.getData("elementid");
                // console.log("ff",data);
                draggables = document.querySelectorAll('.draggable');
                // init();
            })
            container.addEventListener('dragleave', e => {
                e.preventDefault();
            })
            container.addEventListener('dragenter', e => {
                e.preventDefault();
            })
        })


    }

    function getDragAfterElement(container, y) {
    const draggableElements = [...container.querySelectorAll('.draggable:not(.dragging)')]

    return draggableElements.reduce((closest, child) => {
        const box = child.getBoundingClientRect()
        const offset = y - box.top - box.height / 2
        if (offset < 0 && offset > closest.offset) {
        return { offset: offset, element: child }
        } else {
        return closest
        }
    }, { offset: Number.NEGATIVE_INFINITY }).element
    }
body {
    margin: 0;
  }
  
  h1{
    color:#fff;
  }
  .container {
    background-color: #333;
    padding: 1rem;
    margin: 1rem;
    width: 200px;
  }
  
  .draggable {
    padding: 1rem;
    background-color: white;
    border: 1px solid black;
    cursor: move;
  }
  
  .draggable.dragging {
    opacity: .5;
  }
  
#main-container{
    display: flex;
}

  input{
      display: block;
      width:83%;
      height: 0px;
  }

  .main{
      display: flex;
  }
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
 <link rel="stylesheet" type="text/css" href="index.css" >
 
</head>
<body>

    <div class="main">
        <div>
            <div class="draggable" name="text-field" draggable="true">Text Field</div>
            <div class="draggable" name="email-field" draggable="true">Email Field</div>
            <div class="draggable" name="phone-field" draggable="true">Phone Field</div>
        </div>
        <div id="main-container">
            <!-- <div class="container">
                <h1>Section 1</h1>
              <p class="draggable" draggable="true">1</p>
              <p class="draggable" draggable="true">2</p>
            </div>
            <div class="container">
              <h1>Section 2</h1>
              <p class="draggable" draggable="true">3</p>
              <p class="draggable" draggable="true">4</p>
            </div> -->
        </div>
    </div>

  <button id="addsection">Add section</button>
  <script src="index.js"></script>



</body>
</html>

1 个答案:

答案 0 :(得分:0)

最后我不确定这是正确的方法,但是它符合我的要求

function CustomDragAndDrop(){
    this.draggables = undefined;
    this.containers = undefined;
    this.placeholder = undefined;
    this.elementToInsert = undefined;
    this.afterElement = undefined;
    this.sectionCount = 0;
    this.mainContainer = undefined;
    this.existingElement = undefined;

    this.addSection = function(){
        let container = document.createElement('div');
            container.classList.add('container');
        let section = document.createElement('h1');
            section.innerHTML = `Section ${this.sectionCount++}`;
            container.appendChild(section);
            console.log("this main container",this.mainContainer);
        this.mainContainer.appendChild(container);
        this.addEventListenersForContainer(container);
        this.updateContainers();
    }
    this.updateContainers = function(){
        this.containers = document.querySelectorAll('.container');
    }
    this.updateDraggables = function(){
        this.draggables = document.querySelectorAll('.draggable');
    }
    this.addEventListeners = function(name){
        console.log("adding event listeners",this.containers,this.draggables);
        if(name === 'containers' && this.containers){
            this.containers.forEach(container => {
                container.addEventListener('dragover',e => this.onDragHover(e,container,false));
                container.addEventListener('drop',e => this.onDragDrop(e),false);
                container.addEventListener('dragleave',e => this.onDragLeave(e),false);
                container.addEventListener('dragenter',e => this.onDragEnter(e),false);
            });
        }else if('draggables' && this.draggables){
            this.draggables.forEach(draggable => {
                draggable.addEventListener('dragstart',e => this.onDragStart(e,draggable),false);
                draggable.addEventListener('dragend', e => this.onDragEnd(e,draggable),false);
            });
        }else if(this.draggables && this.containers){
            this.containers.forEach(container => {
                container.addEventListener('dragover',e => this.onDragHover(e,container),false);
                container.addEventListener('drop', e => this.onDragDrop(e),false);
                container.addEventListener('dragleave',e => this.onDragLeave(e),false);
                container.addEventListener('dragenter',e => this.onDragEnter(e),false);
            });
            this.draggables.forEach(draggable => {
                draggable.addEventListener('dragstart',e => this.onDragStart(e),false);
                draggable.addEventListener('dragend', e => this.onDragEnd(e),false);
            });
        }
        console.log("draggables",this.draggables);
        console.log("this.containers",this.containers);
    }
    this.removeEventListeners = function(name){
        if(name === 'container' && this.containers){
            this.containers.forEach(container => {
                container.removeEventListener('dragover',e => this.onDragHover(e,container),false);
                container.removeEventListener('drop', e => this.onDragDrop(e),false);
                container.removeEventListener('dragleave',e => this.onDragLeave(e),false);
                container.removeEventListener('dragenter',e => this.onDragEnter(e),false);
            });
        }else if(name === 'draggables' && this.draggables){
            this.draggables.forEach(draggable => {
                draggable.removeEventListener('dragstart',e => this.onDragStart(e,draggable),false);
                draggable.removeEventListener('dragend', e => this.onDragEnd(e,draggable),false);
            });
        }else if(this.draggables && this.containers){
            this.containers.forEach(container => {
                container.removeEventListener('dragover',e => this.onDragHover(e,container),false);
                container.removeEventListener('drop',e => this.onDragDrop(e),false);
                container.removeEventListener('dragleave',e => this.onDragLeave(e),false);
                container.removeEventListener('dragenter',e => this.onDragEnter(e),false);
            });
            this.draggables.forEach(draggable => {
                draggable.removeEventListener('dragstart',e => this.onDragStart(e),false);
                draggable.removeEventListener('dragend',e => this.onDragEnd(e),false);
            });
        }
    }
    this.createPlaceHolder = function(){
        let placeholder = document.createElement('div');
        placeholder.style.height = '50px';
        placeholder.style.borderRadius = '5px';
        placeholder.style.backgroundColor = '#eee';
        placeholder.style.margin = '10px 0';
        this.placeholder = placeholder;
    }
    this.getDragAfterElement = function(container, y){
    const draggableElements = [...container.querySelectorAll('.draggable:not(.dragging)')]
    return draggableElements.reduce((closest, child) => {
        const box = child.getBoundingClientRect()
        const offset = y - box.top - box.height / 2
        if (offset < 0 && offset > closest.offset) {
        return { offset: offset, element: child }
        } else {
        return closest
        }
    }, { offset: Number.NEGATIVE_INFINITY }).element
    }

    this.onDragStart = function(e,draggable){
        e.stopPropagation();
        let elementToInsert;
        console.log("drag start",draggable);
        // e.dataTransfer.setData('elementid',e.target.id);
        if(draggable && draggable.getAttribute('name')){
            let element = draggable.getAttribute('name');
            
            switch(element){
                case 'text-field':
                    elementToInsert = document.createElement('input');
                    elementToInsert.classList.add('draggable');
                    elementToInsert.setAttribute('draggable',true);
                    elementToInsert.setAttribute('placeholder','Text');
                    elementToInsert.setAttribute('disabled',true);
                    elementToInsert.setAttribute('id',`field-${Date.now()}`);
                    this.elementToInsert = elementToInsert;
                    this.existingElement = false;
                    break;
                case 'email-field':
                        elementToInsert = document.createElement('input');
                        elementToInsert.classList.add('draggable');
                        elementToInsert.setAttribute('draggable',true);
                        elementToInsert.setAttribute('placeholder','Email');
                        elementToInsert.setAttribute('disabled',true);
                        elementToInsert.setAttribute('id',`field-${Date.now()}`);
                        this.elementToInsert = elementToInsert;
                        this.existingElement = false;
                        break;
                case 'phone-field':
                    elementToInsert = document.createElement('input');
                    
                    elementToInsert.classList.add('draggable');
                    elementToInsert.setAttribute('draggable',true);
                    elementToInsert.setAttribute('placeholder','Phone');
                    elementToInsert.setAttribute('disabled',true);
                    elementToInsert.setAttribute('id',`field-${Date.now()}`);
                    this.elementToInsert = elementToInsert;
                    this.existingElement = false;
                    break;
                default:
                    this.elementToInsert = draggable;
                    this.existingElement = true;
                    break;
            }
        }else{
            this.existingElement = true;
            this.elementToInsert = draggable; 
        }
        this.placeholder.setAttribute("id",`placeholder-${Date.now()}`);
        draggable.classList.add('dragging');
    }
    this.onDragEnd = function(e,draggable){
        draggable.classList.remove('dragging');
        console.log("drag end",this.elementToInsert);
        if(!this.existingElement){
            this.addEventListenerForDraggableItem(this.elementToInsert);
            this.updateDraggables('draggables');
        }else{
            console.log("existing ele",this.elementToInsert);
            this.elementToInsert.classList.remove('dragging');
        }
    }
    this.addEventListenerForDraggableItem = function(element){
        console.log("ele",element);
        element.addEventListener('dragstart',e => this.onDragStart(e,element));
        element.addEventListener('dragend',e => this.onDragEnd(e,element));
    }

    this.addEventListenersForContainer = function(container){
        container.addEventListener('dragover',e => this.onDragHover(e,container,false));
        container.addEventListener('drop',e => this.onDragDrop(e),false);
        container.addEventListener('dragleave',e => this.onDragLeave(e),false);
        container.addEventListener('dragenter',e => this.onDragEnter(e),false);
    }

    this.onDragHover = function(e,container){
        e.preventDefault();
        this.afterElement = this.getDragAfterElement(container, e.clientY);
        if (this.afterElement == null) {
            container.appendChild(this.placeholder)
        } else {
            container.insertBefore(this.placeholder, this.afterElement)
        }
    }
    this.onDragEnter = function(e){
        e.preventDefault();
    }
    this.onDragLeave = function(e){
        e.preventDefault();
        console.log("on drag leave");
    }
    this.onDragDrop = function(e){
        e.preventDefault()
        // let data = e.dataTransfer.getData("elementid");
        this.placeholder.replaceWith(this.elementToInsert);
    }

    this.init = function(){
        try{
            this.mainContainer = document.getElementById('main-container');
            this.updateContainers();
            this.updateDraggables();
            this.addEventListeners();
            this.createPlaceHolder();
        }catch(e){
            console.log(e);
        }
    }
}

let customDragnDrop = new CustomDragAndDrop();
customDragnDrop.init();
body {
    margin: 0;
  }
  
  h1{
    color:#fff;
  }
  .container {
    background-color: #333;
    padding: 1rem;
    margin: 1rem;
    width: 200px;
  }
  
  .draggable {
    padding: 1rem;
    background-color: white;
    border: 1px solid black;
    cursor: move;
  }
  
  .draggable.dragging {
    opacity: .5;
  }
  
#main-container{
    display: flex;
}

  input{
      display: block;
      width:83%;
      height: 0px;
  }

  .main{
      display: flex;
  }
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
 <link rel="stylesheet" type="text/css" href="index.css" >
 
</head>
<body>

    <div class="main">
        <div>
            <div class="draggable" id="text" name="text-field" draggable="true">Text Field</div>
            <div class="draggable" id="email" name="email-field" draggable="true">Email Field</div>
            <div class="draggable" id="phone" name="phone-field" draggable="true">Phone Field</div>
        </div>
        <div id="main-container">
            <!-- <div class="container">
                <h1>Section 1</h1>
              <p class="draggable" draggable="true">1</p>
              <p class="draggable" draggable="true">2</p>
            </div>
            <div class="container">
              <h1>Section 2</h1>
              <p class="draggable" draggable="true">3</p>
              <p class="draggable" draggable="true">4</p>
            </div> -->
        </div>
    </div>

  <button onclick="customDragnDrop.addSection()">Add section</button>
  <script src="index.js"></script>



</body>
</html>