【问题标题】:Drag and drop file using ExtJS 6使用 ExtJS 6 拖放文件
【发布时间】:2015-11-06 08:58:00
【问题描述】:

我目前有一个 webapp,其视图是使用 ExtJS 6 编写的:我们目前使用 Java 小程序,其目的是允许用户将文件从文件系统拖放到 Web 服务器。 我的目标是删除该小程序,并使用 ExtJS6 处理拖放:这可能吗?

我试图在文档中搜索它,但我发现的唯一主题 (https://docs.sencha.com/extjs/6.0/core_concepts/drag_drop.html) 是关于拖放框架元素的。

【问题讨论】:

  • 拖放基本上将 DOM 节点从一个容器拖到另一个容器,因此您实际上不是在拖动文件,而是在拖动代表文件的节点。您打算如何列出您的文件系统?您打算如何访问您的文件系统? PHP + 树形面板? HTML5 + 树形面板?
  • 感谢您的提问:我认为,就我而言,最好的选择是 HTML5 + TreePanel

标签: java extjs drag-and-drop applet extjs6


【解决方案1】:

fiddle 中包含的窗口允许用户将文件从文件系统拖放到 Web 服务器。

源代码:

Ext.application({
  name: 'Fiddle',

  launch: function() {

      var store = Ext.create('Ext.data.Store', {
          fields: ['name', 'size', 'file', 'status']
      });

      var postDocument = this.postDocument;

      Ext.widget('container', {

          renderTo: Ext.getBody(),

          items: [{
              multiSelect: true,
              xtype: 'grid',
              id: 'UploadGrid',
              columns: [{
                  header: 'Name',
                  dataIndex: 'name',
                  flex: 2
              }, {
                  header: 'Size',
                  dataIndex: 'size',
                  flex: 1,
                  renderer: Ext.util.Format.fileSize
              }, {
                  header: 'Status',
                  dataIndex: 'status',
                  flex: 1,
                  renderer: this.rendererStatus
              }],

              viewConfig: {
                  emptyText: 'Drop Files Here',
                  deferEmptyText: false
              },
              store: store,

              listeners: {

                  drop: {
                      element: 'el',
                      fn: 'drop'
                  },

                  dragstart: {
                      element: 'el',
                      fn: 'addDropZone'
                  },

                  dragenter: {
                      element: 'el',
                      fn: 'addDropZone'
                  },

                  dragover: {
                      element: 'el',
                      fn: 'addDropZone'
                  },

                  dragleave: {
                      element: 'el',
                      fn: 'removeDropZone'
                  },

                  dragexit: {
                      element: 'el',
                      fn: 'removeDropZone'
                  },

              },

              noop: function(e) {
                  e.stopEvent();
              },

              addDropZone: function(e) {
                  if (!e.browserEvent.dataTransfer || Ext.Array.from(e.browserEvent.dataTransfer.types).indexOf('Files') === -1) {
                      return;
                  }

                  e.stopEvent();

                  this.addCls('drag-over');
              },

              removeDropZone: function(e) {
                  var el = e.getTarget(),
                      thisEl = this.getEl();

                  e.stopEvent();


                  if (el === thisEl.dom) {
                      this.removeCls('drag-over');
                      return;
                  }

                  while (el !== thisEl.dom && el && el.parentNode) {
                      el = el.parentNode;
                  }

                  if (el !== thisEl.dom) {
                      this.removeCls('drag-over');
                  }

              },

              drop: function(e) {
                  e.stopEvent();
                  Ext.Array.forEach(Ext.Array.from(e.browserEvent.dataTransfer.files), function(file) {
                      store.add({
                          file: file,
                          name: file.name,
                          size: file.size,
                          status: 'Ready'

                      });
                  });
                  this.removeCls('drag-over');
              },

              tbar: [{
                  text: "Upload",
                  handler: function() {
                      for (var i = 0; i < store.data.items.length; i++) {
                          if (!(store.getData().getAt(i).data.status === "Uploaded")) {
                              store.getData().getAt(i).data.status = "Uploading";
                              store.getData().getAt(i).commit();
                              //replace "insert your upload url here" with the real url
                              postDocument("insert your upload url here", store, i);
                          }
                      }

                  }
              }, {
                  text: "Erase EVERYTHING",
                  handler: function() {
                      store.reload();
                  }
              }, {
                  text: "Erase uploaded files",
                  handler: function() {
                      for (var i = 0; i < store.data.items.length; i++) {
                          var record = store.getData().getAt(i);
                          if ((record.data.status === "Uploaded")) {
                              store.remove(record);
                              i--;
                          }
                      }
                  }
              }, {
                  text: "Erase selected files",
                  handler: function() {
                      store.remove(Ext.getCmp('UploadGrid').getSelection());
                  }
              }]


          }],

          padding: 20


      });

  },

  rendererStatus: function(value, metaData, record, rowIndex, colIndex, store) {
      var color = "grey";
      if (value === "Ready") {
          color = "blue";
      } else if (value === "Uploading") {
          color = "orange";
      } else if (value === "Uploaded") {
          color = "green";
      } else if (value === "Error") {
          color = "red";
      }
      metaData.tdStyle = 'color:' + color + ";";
      return value;
  },

  postDocument: function(url, store, i) {
      var xhr = new XMLHttpRequest();
      var fd = new FormData();
      fd.append("serverTimeDiff", 0);
      xhr.open("POST", url, true);
      fd.append('index', i);
      fd.append('file', store.getData().getAt(i).data.file);
      //xhr.setRequestHeader("Content-Type","multipart/form-data");
      xhr.setRequestHeader("serverTimeDiff", 0);
      xhr.onreadystatechange = function() {
          if (xhr.readyState == 4 && xhr.status == 200) {
              //handle the answer, in order to detect any server side error
              if (Ext.decode(xhr.responseText).success) {
                  store.getData().getAt(i).data.status = "Uploaded";
              } else {
                  store.getData().getAt(i).data.status = "Error";
              }
              store.getData().getAt(i).commit();
          } else if (xhr.readyState == 4 && xhr.status == 404) {
              store.getData().getAt(i).data.status = "Error";
              store.getData().getAt(i).commit();
          }
      };
      // Initiate a multipart/form-data upload
      xhr.send(fd);
  }
});

【讨论】:

    【解决方案2】:

    为了支持文件的拖放,您可以使用以下events
    dropdragstartdragenterdragoverdragleavedragexit

    一个工作示例:https://fiddle.sencha.com/#fiddle/10v9

    Ext.application({
        name: 'Fiddle',
    
        launch: function() {
    
            var store = Ext.create('Ext.data.Store', {
                fields: ['name', 'size', 'file']
            });
    
            Ext.widget('container', {
    
                renderTo: Ext.getBody(),
    
                items: [{
                    xtype: 'grid',
    
                    columns: [{
                        header: 'Name',
                        dataIndex: 'name',
                        flex: 2
                    }, {
                        header: 'Size',
                        dataIndex: 'size',
                        flex: 1,
                        renderer: Ext.util.Format.fileSize
                    }],
    
                    viewConfig: {
                        emptyText: 'Drop Files Here',
                        deferEmptyText: false
                    },
                    store: store,
    
                    listeners: {
    
                        drop: {
                            element: 'el',
                            fn: 'drop'
                        },
    
                        dragstart: {
                            element: 'el',
                            fn: 'addDropZone'
                        },
    
                        dragenter: {
                            element: 'el',
                            fn: 'addDropZone'
                        },
    
                        dragover: {
                            element: 'el',
                            fn: 'addDropZone'
                        },
    
                        dragleave: {
                            element: 'el',
                            fn: 'removeDropZone'
                        },
    
                        dragexit: {
                            element: 'el',
                            fn: 'removeDropZone'
                        },
    
                    },
    
                    noop: function(e) {
                        e.stopEvent();
                    },
    
                    addDropZone: function(e) {
                        if (!e.browserEvent.dataTransfer || Ext.Array.from(e.browserEvent.dataTransfer.types).indexOf('Files') === -1) {
                            return;
                        }
    
                        e.stopEvent();
    
                        this.addCls('drag-over');
                    },
    
                    removeDropZone: function(e) {
                        var el = e.getTarget(),
                            thisEl = this.getEl();
    
                        e.stopEvent();
    
    
                        if (el === thisEl.dom) {
                            this.removeCls('drag-over');
                            return;
                        }
    
                        while (el !== thisEl.dom && el && el.parentNode) {
                            el = el.parentNode;
                        }
    
                        if (el !== thisEl.dom) {
                            this.removeCls('drag-over');
                        }
    
                    },
    
                    drop: function(e) {
                        e.stopEvent();
    
                        Ext.Array.forEach(Ext.Array.from(e.browserEvent.dataTransfer.files), function(file) {
                            store.add({
                                file: file,
                                name: file.name,
                                size: file.size
                            });
                            console.log(file);
                        });
    
                        this.removeCls('drag-over');
                    }
    
    
                }],
    
                padding: 20
    
    
            });
    
        }
    });
    

    【讨论】:

    • 感谢您的回答:我查看了您的代码。我认为,为了将删除的文件提交到服务器,我必须实例化一个 FileReader(就像这个示例提供的 fiddle.sencha.com/#fiddle/n9t 一样),并向服务器提交一个 Ajax POST 请求,对吗?
    • 我认为你不需要FileReader,你可以使用FormData
    【解决方案3】:

    我正在使用我在 sencha 论坛中找到的解决方案:

    Ext.define('FileDropper', {
        extend: 'Ext.plugin.Abstract',
        alias: 'plugin.filedropper',
    
        overCls: '',
    
        init: function(c) {
            this.target = c;
            c.on({
                element: 'el',
                scope: this,
                dragover: this.onDragOver,
                dragenter: this.onDragEnter,
                dragLeave: this.onDragLeave,
                drop: this.onDrop
            });
        },
    
        onDragOver: function(e) {
            e.stopEvent();
        },
    
        onDragEnter: function(e) {
            this.target.addCls(this.overCls);
            e.stopEvent();
        },
    
        onDragLeave: function() {
            this.target.removeCls(this.overCls);
        },
    
        onDrop: function(e) {
            var callback = this.callback,
                scope = this.scope || this;
    
            e.stopEvent();
            this.target.removeCls(this.overCls);
            if (callback) {
                callback.call(scope, e.browserEvent.dataTransfer.files);
            }
        }
    });
    

    像这样将插件添加到您的视图中:

    Ext.define('MyPanel', {
        extend: 'Ext.Panel',
    
        // ... your content
    
        plugins: [{
            ptype: 'filedroppper'
            overCls: 'foo'
            callback: function(files) {
                // handle your upload
            }
        }]
    });
    

    您只需在回调中处理删除的文件:

        callback: function (files) {
            var url = 'example.org'
            var xhr = new XMLHttpRequest();
            var fd = new FormData();
    
            xhr.open("POST", url, true);
            xhr.onreadystatechange = function () {
                if (xhr.readyState == 4 && xhr.status == 200) {
                    // Handle response.
                    alert(xhr.responseText); // handle response.
                }
            };
    
            for (var i = 0; i < files.length; i++) {
                fd.append('files', files.item(i));
            }
    
            // Initiate a multipart/form-data upload
            xhr.send(fd);
        }
    

    但如果您使用FormData(),请确保您不必支持旧浏览器。

    【讨论】:

    • 感谢您的回答:很遗憾,我无法打开链接(我没有访问该页面的权限)。
    • 我更新了我的答案并添加了我写的插件。
    猜你喜欢
    • 2012-01-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-17
    • 2013-12-27
    • 2017-04-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多