Front-end implementation of file upload (click+drag)

1. Introduction

The upload component of element has been used in the Vue project before, and two upload functions of click upload + drag and drop upload have been realized. Then I was thinking whether it is possible to realize click upload and drag and drop upload of files through native html+js, just do it.
The first is to click to get the uploaded file. Naturally, you only need to use inputthe label, but the original click to upload button is too simple, so my idea is to use a div to simulate the upload button, and then monitor its click event. By input.click()going to simulate clicking on the real upload element.
Then drag and drop to get the uploaded file, which is a little difficult. My idea is to use the new dragdrag and drop API+ of HTML5 dataTransferto realize the drag and drop of the file, but because it is new in html5, it may be viewed in some low-version IE The browser is not compatible, so if you want to use it in an actual enterprise project, you need to pay attention to compatibility issues ( IE damn! ).

Finally, when we get the uploaded file, we can formDateupload the file with the help of objects and ajax tools (native, jquery, axios, etc.), and we can also xhr.upload.onprogressdisplay it on the page by getting the progress of the file upload.

Two, get the file

1. Page effect

insert image description here

2. Click and drag to upload the obtained file result

insert image description here

3. Specific code

  <style>
    .box {
      
      
      width: 300px;
      height: 300px;
      margin: 50px auto;
      padding-top: 30px;
      background-color: #f5f5f5;
      border-radius: 10px;
    }
    .btn {
      
      
      width: 200px;
      height: 30px;
      line-height: 30px;
      margin: 10px auto;
      text-align: center;
      color: #5098F8;
      border-radius: 4px;
      border: 1px dashed #5098F8;
      cursor: pointer;
    }
  </style>
  
<body>
  <!-- 这个id属性放在哪个盒子里面 哪个盒子的范围就是拖拽上传的范围 -->
<div class="box" id="drop">
  <!-- 用来展示的上传按钮 -->
  <div class="btn" id="btn">点击上传按钮</div>
  <!-- 实际实现上传的input 并限制文件类型(不保险,因为用户可以放手放开限制,选择所有类型文件,所以需要在上传之前进行第二次验证) -->
  <input type="file" id="file-btn" onchange="selectFile(event)" accept=".doc,.docx" style="display: none;">
</div>

<script>
  var file = null // 要进行上传的文件
  // 给上传按钮绑定点击事件
  document.querySelector('#btn').onclick = function() {
      
      
    // 模拟点击上传的input 弹出文件选择框
    document.querySelector('#file-btn').click()
  }
  // 获取点击上传  选择的文件
  function selectFile(e) {
      
      
    // 通过 e.target.files 获取到选择的文件 此处默认选择一个文件
    console.log('获取点击上传的文件---',e.dataTransfer.files[0]);
    // 第二次验证选择的文件类型是否正确
    if(e.target.files[0].type == 'application/msword' || e.target.files[0].type == 'application/vnd.openxmlformats-officedocument.wordprocessingml.document') {
      
      
      file = e.target.files[0]
    } else {
      
      
      alert('请选择正确的文件类型')
    }
  }

  // 拖拽上传获取对应文件
  let dropBox=document.querySelector('#drop');
      // 当文件在目标元素内移动时
      dropBox.addEventListener('dragover',function(e){
      
      
        // 阻止事件冒泡
        e.stopPropagation();
        // 阻止默认事件(与drop事件结合,阻止拖拽文件在浏览器打开的默认行为)
        e.preventDefault();
      })
      // 当拖拽文件在目标元素内松开时
      dropBox.addEventListener('drop',function(e){
      
      
        // 阻止事件冒泡
        e.stopPropagation();
        // 阻止默认事件(与dragover事件结合,阻止拖拽文件在浏览器打开的默认行为)
        e.preventDefault();
        // 获取拖拽上传的文件(files是个数组 此处默认限制只能上传一个)
        console.log('获取拖拽上传的文件---',e.dataTransfer.files[0]);
        // 第二次验证选择的文件类型是否正确
        if(e.dataTransfer.files[0].type == 'application/msword' || e.dataTransfer.files[0].type == 'application/vnd.openxmlformats-officedocument.wordprocessingml.document') {
      
      
          file = e.dataTransfer.files[0]
        } else {
      
      
          alert('请选择正确的文件类型')
        }
      })
</script>
</body>
Note: The user manually releases the restriction operation (here we take the mac computer as an example, and the windows computer is similar), only need the following three steps:

insert image description here

3. Upload

We need to use formDateobjects and ajax tools (native, jquery, axios, etc.) to upload files, and we can also obtain the xhr.upload.onprogressprogress of file uploads and display them on the page, but what we obtain xhr.upload.onprogressis only the progress of file uploads to the server, and It does not include the server processing and the part of time based on the front-end response, so after the front-end file is uploaded to 100%, it will stagnate for a period of time to get the response from the server.
Here are two ways: native ajax and axios.

1. Native ajax

	  // 上传函数
      function uplaod() {
    
    
        // 创建 FormData 对象
        var formData = new FormData();
        // 将获得文件对象追加到 FormData 对象中
        formData.append('file',file)
        // 创建 xhr 对象
        var xhr = new XMLHttpRequest()
        // 调用 open 函数,指定请求类型与URL地址。其中,请求类型必须为 POST
        xhr.open('POST', 'www.baidi.com')
        // 发起请求
        xhr.send(fd)
        // 监听 xhr.upload 的 onprogress 事件 获取上传进度
        xhr.upload.onprogress = function(e) {
    
    
            // e.lengthComputable 是一个布尔值,表示当前上传的资源是否具有可计算的长度
            if (e.lengthComputable) {
    
    
            	// Math.round() 进行四舍五入取整 因为上传时 网络等不确定因素可能会出现缺失小部分字节的情况 
                // e.loaded 已传输的字节
                // e.total 需传输的总字节
                var progress = Math.round((e.loaded / e.total) * 100) + '%'
            }
        }
        // 是否上传成功
        xhr.onreadystatechange = function() {
    
    
          if (xhr.readyState === 4 && xhr.status === 200) {
    
    
            var data = JSON.parse(xhr.responseText)
            if (data.status === 200) {
    
    
              console.log('上传文件成功');
            }
          }
        }

2、axios(vue)

      // 上传函数(vue中)
      async uplaod() {
    
    
        // 创建 FormData 对象
        var formData = new FormData();
        // 将获得文件对象追加到 FormData 对象中
        formData.append('file',file)
        try {
    
    
	        // 暂存this对象
	        const that = this
	        // 调用接口开始上传
	        await this.$axios.post(api.addfiles, formData, {
    
    
	          // 实时获取上传进度
	          onUploadProgress (progressEvent) {
    
    
	          	// Math.round() 进行四舍五入取整 因为上传时 网络等不确定因素可能会出现缺失小部分字节的情况 
	            // loaded 已传输的字节
	            // total 需传输的总字节
	            that.progress = Math.round((progressEvent.loaded / progressEvent.total) * 100) + '%'
	        }
	        console.log('上传成功')
	     } catch(error) {
    
    
		 	console.log('上传失败',error)
		 }
        

Guess you like

Origin blog.csdn.net/weixin_45092437/article/details/128436238