HTML / Javascript是否支持将图像拖到网页上?

时间:2018-03-10 10:05:50

标签: javascript html5

HTML5 / Javascript是否支持将图片拖到网页上?

我是否可以创建一个网页,允许用户将图像从其他网站直接拖到我网站上的占位符(所有客户端),然后使用其他按钮将该图像上传回服务器?

1 个答案:

答案 0 :(得分:3)

我无法确定所有浏览器在这种情况下的行为/做/将如何表现,但我所看到的是,当您从网页拖动图像并将其拖放到网页时(相同或另一个),浏览器不会从中创建文件(或Blob),只会创建它的标记。

这意味着在这种情况下您仍将受到跨源策略的束缚,即您将无法访问图像文件的数据,因此无法将其发送到您的服务器

但这不会阻止您在页面上显示此图片,也不会阻止您抓取src

所以你可以做的是处理两个案件:

  1. 您的用户从其文件系统中删除文件:您必须将其发送到您的服务器,最好通过FormData作为multipart。要显示它,请创建一个新的<img>元素,并将其src设置为由文件制作的blobURI。
  2. 他们从其他网页上删除:dataTransfer应包含text/html项。如果是这样,请尝试解析它并查找现有的<img>元素。如果有,您可以在当前文档中采用它们进行显示。但是,要将其保存在服务器上,您必须直接从服务器获取(不受同源策略限制),因此您必须将此URI发送到服务器。
  3. var dropzone = document.getElementById('dropzone'),
      send_btn = document.getElementById('send'),
      res = document.getElementById('res'),
      imgList = [];
    
    dropzone.ondragover = function ondragover(e) {
      e.preventDefault();
      dropzone.classList.add('dragover');
    };
    dropzone.ondrop = function ondrop(e) {
      e.preventDefault();
      dropzone.classList.remove('dragover');
      // try to get images from this dropevent
      var imageObjects = retrieveImageData(e.dataTransfer);
      if (!imageObjects) return;
      imageObjects.forEach(function appendToDoc(imgObj) {
        res.appendChild(imgObj.element);
      });
      // store it
      imgList = imgList.concat(imageObjects);
      if (imageObjects.length)
        send_btn.disabled = false;
    };
    dropzone.ondragexit = function(ondragexit) {
      dropzone.classList.remove('dragover');
    };
    
    function retrieveImageData(dT) {
      // first try to get Files
      var files = getFiles(dT);
      if (files.length) {
        return files;
      }
      // if none, try to get HTMLImage or SVGImage
      var elems = getHTMLMarkup(dT);
      if (elems && elems.length) {
        return elems;
      }
      // we could also try to getData('text/plain') hoping for an url
      // but this might not be such a good idea...
      console.warn('unable to retrieve any image in dropped data');
    }
    
    function getFiles(dT) {
      // quite simple: won't traverse folders
      var files = [],
        imgObj;
      if (dT.files && dT.files.length) {
        for (var i = 0; i < dT.files.length; i++) {
          // only image Files
          if (dT.files[i].type.indexOf('image/') === 0) {
            imgObj = {
              type: 'file',
              element: new Image(),
              file: dT.files[i]
            };
            imgObj.element.onerror = onIMGError;
            imgObj.element.src = URL.createObjectURL(imgObj.file);
            files.push(imgObj);
          }
        }
      }
      return files;
    }
    
    function getHTMLMarkup(dT) {
      var markup = dT.getData('text/html');
      if (markup) {
        var doc = new DOMParser().parseFromString(markup, 'text/html');
        var imgs = doc && doc.querySelectorAll('img,image') ||  [];
        imgs.forEach(toImageObject);
        return Array.prototype.map.call(imgs, toImageObject);
      }
    
      function toImageObject(element) {
        var img;
        if (element instanceof SVGImageElement) {
          img = new Image();
          img.src = element.getAttributeNS('http://www.w3.org/1999/xlink', 'href') ||
            element.getAttribute('href');
        } else {
          img = document.adoptNode(element);
        }
        img.onerror = onIMGError;
        return {
          type: 'element',
          element: img
        };
      }
    }
    // Once we got everything, time to retrieve our objects
    send_btn.onclick = function sendData() {
      var fD = new FormData();
      // send Files data directly
      var files = imgList.filter(function isFile(obj) {
        return obj.type === 'file';
      });
      files.forEach(function appendToFD(obj) {
        fD.append('files[]', obj.file);
      });
      // for elems, we will need to grab the data from the server
      var elems = imgList.filter(function isElem(obj) {
        return obj.type === "element";
      });
      var urls = elems.map(function grabURL(obj) {
        return obj.element.src;
      });
      if (urls.length)
        fD.append('urls', JSON.stringify(urls));
    
      sendFormData(fD);
    };
    
    function sendFormData(fD) {
      var xhr = new XMLHttpRequest();
      xhr.open('POST', 'your_url');
      // you would normally send it
      //xhr.send(fD);
    
      // but here we will just log the formData's content
      var files = fD.getAll('files[]');
      console.log('files: ', files);
      var urls = fD.get('urls');
      console.log('urls', urls);
    }
    // in case we can't load it
    function onIMGError() {
      var img = this;
      var index = -1;
      imgList.forEach(function search(obj, i) {
        if (index < 0 && obj && obj.element === img)
          index = i;
      });
      // remove from our list
      if (index > -1) {
        imgList.splice(index, 1);
        if (img.parentNode) img.parentNode.removeChild(img);
      }
    }
    #dropzone {
      width: 300px;
      height: 150px;
      border: 1px solid black;
    }
    
    #dropzone.dragover {
      background: rgba(0, 0, 0, .5);
    }
    
    #res {
      border: 1px solid black;
    }
    <div id="dropzone">drop here</div>
    <button id="send" disabled>log saved objects</button>
    <div id="res">results:<br></div>

    另请注意,contenteditable容器的默认设置是显示此<img>。我不想在这个足够长的例子中整合这个案例,但我确信你会找到一种方法来处理它。如果需要的话。