VUE组件系列7:文件上传2

本文介绍了一个自定义的拖放上传组件,支持拖放、复制粘贴上传文件,并展示了如何使用Vue.js实现文件上传功能,包括文件展示、上传进度、预览及取消上传等特性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

支持拖放上传

支持鼠标右键和Ctrl+v方式上传

就是有点丑,样式慢慢优化。。。。。。。。。

 <template>
  <div
    class="pre_upload"
    @drop="okdrop($event)"
    @dragover="allowDrop($event)"
    v-on:paste="fun_paste($event)"
  >
    <div class="pre_leve_one"></div>
    <div class="pre_leve_two">
      <h4>请把文件拖放到这里来上传</h4>
      <div id="files_data" class="pre_files_data" v-show="show_tab">
        <table class="pre_dataintable">
          <thead>
            <tr>
              <th>序号</th>
              <th>单号</th>
              <th>名称</th>
              <th>类型</th>
              <th>Y/N</th>
              <th>大小</th>
              <th>进度</th>
              <th>操作</th>
            </tr>
          </thead>
          <tbody>
            <tr v-for="(item, index) in pre_flies" :key="index">
              <td>{{ item.id }}</td>
              <td>{{ item.sheet_no }}</td>
              <td class="pre_tab_name">
                {{ item.name }}
              </td>
              <td>{{ item.type }}</td>
              <td>{{ item.flag }}</td>
              <td>{{ item.size }}&nbsp;KB</td>
              <td>{{ item.up }}</td>
              <td>
                <button class="pre_btn_canle" @click="del_files(item.id)">
                  取消上传
                </button>
                <button class="pre_btn_ok" @click="lookImage(item)">
                  预览图片
                </button>
              </td>
            </tr>
          </tbody>
        </table>
        <div>
          <button class="pre_btn_del_all" @click="canle_all">全部取消</button
          >&nbsp;&nbsp;
          <button class="pre_btn_up" @click="submit_files">上传</button>
        </div>
      </div>

      <!-- 使用画布验证上传图片转换是否正确  -->
      <!-- <p>画布:</p>
      <canvas
        id="myCanvas"
        width="500"
        height="300"
        style="border:1px solid #d3d3d3;background:#ffffff;"
      >
      Your browser does not support the HTML5 canvas tag.
      </canvas>-->
      <!-- 画布验证过程有异步 还是img直接 -->
    </div>
    <div>
      <p>
        注意:复制黏贴实现方式为,使用鼠标右键里的复制,然后使用Ctrl+v到指定区域,才可以上传文件。
      </p>
      <p>Ctrl+c然后Ctrl+v方式无法上传文件。</p>
    </div>
    <!-- 弹出向导层 start-->
    <div id="pop" class="pop_img" v-show="show_img">
      <div class="pop_head">
        <a class="close" href="javascript:void(0);" @click="hide()"></a>
      </div>
      <div id="pop_bodyup" class="pre_show_img">
        <img :src="imgsrc" />
      </div>
    </div>
    <!-- 弹出向导层 end-->
    <per-message :message_data="msg_obj" />
  </div>
</template> 

<script>
/*
名称:拖放上传组件
日期:2019-03-14
作者:hj
目标:
1、将拖放的文件名称展示出来:拖放过来的有可能是一堆文件和文件夹混合 当放置被拖数据时,会发生 drop 事件。
2、显示上传文件的进度
3、最好可以支持预览
4、2019-05-16 增加对复制黏贴上传方式的支持 

*/
import '@/assets/css/pop.css';
import { base_encode } from "@/utils/base64.js";
import { GetShort,DeleteSpecialWord } from "@/utils/localstore.js";
import { BrowserGet } from "@/utils/systemSelect.js";

export default {
  name: "pre_upfile",
  components: {    
    'per-message':()=>import("./pre_message.vue")
  }, 
  data() {
    return {
      pre_flies: [],
      exist_data: [],
      show_tab: false,
      show_img:false,
      imgsrc: "",
      msg_obj:{},
      ok_name:''
    };
  }, 
  props: {
    post_action:String,
    sheet_no:String
  },  
  methods: {
    okdrop: async function(ev) {
      // 调用 preventDefault() 来避免浏览器对数据的默认处理(drop 事件的默认行为是以链接形式打开)
      ev.preventDefault();

      //绑定单号校验
      if(this.sheet_no===undefined || this.sheet_no==null || this.sheet_no==''){
        this.msg_obj={'showtype':'warning','note':'请您先选择要上传的文件的对应业务单据'};
        return;
      }
      // 通过 dataTransfer.getData("Text") 方法获得被拖的数据。该方法将返回在 setData() 方法中设置为相同类型的任何数据。
      // var data=ev.dataTransfer.getData("Text");
      var back_data = [],
        ok_data = [];
      back_data = ev.dataTransfer.files; //获取文件           
      for (var i = 0; i < back_data.length; i++) {
        var td = {};
        td.id = i + 1;
        this.check_file_name(back_data[i].name);
        td.name = this.ok_name;
        
        td.type = back_data[i].type;
        // td.size=Math.round(Number(back_data[i].size)/1024);
        td.size = (Number(back_data[i].size) / 1024).toFixed(0);
        if (
          String(td.type)
            .toLowerCase()
            .indexOf(".exe") > 0
        ) {
          td.flag = "NO";
        } else {
          td.flag = "YES";
        }
        td.up = 0 + "%";
        td.sheet_no=this.sheet_no;  //当前点击选择 的单号
        td.filedata = await this.convertFileToString(back_data[i]);        
        ok_data[i] = td;
      }
      var j = 0;
      j = this.exist_data.length; 
      if (j > 0) {
        for (var i = 0; i < ok_data.length; i++) {
          this.exist_data[j] = ok_data[i];
          j += 1;
        }
        // 如果是多次拖放,需要进行二次整理
        var temp_d=[];
        for(var i=0;i<this.exist_data.length;i++){
          var temp_o={};
          temp_o.id = i + 1;
          temp_o.name = this.exist_data[i].name;
          temp_o.type = this.exist_data[i].type;
          temp_o.size = this.exist_data[i].size;
          temp_o.flag = this.exist_data[i].flag;
          temp_o.up = this.exist_data[i].up;
          temp_o.filedata= this.exist_data[i].filedata;
          temp_o.sheet_no= this.exist_data[i].sheet_no;
          temp_d[i]=temp_o;
        }
        this.pre_flies=temp_d;
      } else {
        this.exist_data = ok_data;
        this.pre_flies = this.exist_data;
      }
      
     
      this.show_tab = true;
      // var tf=document.getElementById("files_data");
      // tf.target.appendChild(files);
    },
    allowDrop: function(ev) {
      ev.preventDefault();
    },
    convertFileToString: function(tempfile) {
      return new Promise(resolve => {
        var tf = new FileReader();
        tf.readAsDataURL(tempfile);
        tf.onload = function() {
          resolve(this.result);
        };
      });
    },
    submit_files: async function() {
      this.exist_data = [];
      for (var i = 0; i < this.pre_flies.length; i++) {
        /*这块应该还可以用vuex 封装*/ 
        var postdata = "";
        postdata =
          '{"action":"'+this.post_action+'","user_no":"' +
          GetShort("userno") +
          '","upfile_name":"' +
          DeleteSpecialWord(this.pre_flies[i].name) +
          '","upfile_type":"' +
          this.pre_flies[i].type +
          '","upfile_size":"' +
          this.pre_flies[i].size +
          '","upfile_data":"' +
          this.pre_flies[i].filedata +
          '","sheet_no":"' +
          this.pre_flies[i].sheet_no +
          '"}';
        postdata =
          '{"method":"File_load","data":"' + base_encode(postdata) + '"}';
        var tp = this.pre_flies[i];
        await this.updatabyquere(postdata, tp);
      }
    },
    updatabyquere: function(postdata, tp) {
      // try {
        this.$postfile(
          "/Data_Back",
          postdata,
          res => {
            var loaded = 0,
              total = 0;
            loaded = res.loaded;
            total = res.total;
            this.$nextTick(() => {
              // console.log(tp);
              tp.up = ((loaded / total) * 100).toFixed(2) + " %";
            });
          }
        ).then(res => {          
            res = JSON.parse(res);
            console.log(res);
            res = res.data;
            if (res.status == 1) {
              tp.up = "上传成功";
              this.msg_obj={'showtype':'ok','note':'上传成功'};
            } else {
              tp.up = "上传失败";
              this.msg_obj={'showtype':'ok','note':'上传失败\n\r'+res.msg};
            }
          
        });
      // } 
      // catch (ex) {
      //     tp.up = "上传失败\r\n"+ex;
      // }
    },
    del_files: function(id) {
      var data = []; 
      var j=0;
      for (var i = 0; i < this.pre_flies.length; i++) {        
        if (this.pre_flies[i].id != id) {
          data[j] = this.pre_flies[i];
          j+=1;
        }
      }
      this.pre_flies = data;
      if (this.pre_flies.length == 0) {
        this.show_tab = false;
      }
    },
    canle_all: function() {
      this.pre_flies = [];      
      this.exist_data = [];
      this.show_tab = false;
    },
    lookImage:function(parm){
      console.log('进来'+parm.name);
      if (/\.(gif|jpg|jpeg|png|GIF|JPG|PNG|ico|pdf)$/.test(parm.name)) {
        this.imgsrc=parm.filedata;
        this.show_img=true;
      }
    },
    closeImage:function(parm){
      console.log('出去');
      this.show_img=false;
    },
    hide:function(){
      this.show_img=false;
    },
    fun_paste:async function(e){
      var browserType=BrowserGet();
      console.log('浏览器类型 '+browserType);
      //绑定单号校验
      if(this.sheet_no===undefined || this.sheet_no==null || this.sheet_no==''){
        this.msg_obj={'showtype':'warning','note':'请您先选择要上传的文件的对应业务单据'};
        return;
      }
      var back_data = [],ok_data = [];
      if(browserType=='chrome' || browserType=='firefox' ){
        // console.log(e.clipboardData);
        // console.log(e.clipboardData.files);          
        
        back_data = e.clipboardData.files; //获取文件           
        for (var i = 0; i < back_data.length; i++) {
          var td = {};
          td.id = i + 1;
          this.check_file_name(back_data[i].name);
          td.name = this.ok_name;
          td.type = back_data[i].type;
          // td.size=Math.round(Number(back_data[i].size)/1024);
          td.size = (Number(back_data[i].size) / 1024).toFixed(0);
          if (
            String(td.type)
              .toLowerCase()
              .indexOf(".exe") > 0
          ) {
            td.flag = "NO";
          } else {
            td.flag = "YES";
          }
          td.up = 0 + "%";
          td.sheet_no=this.sheet_no;  //当前点击选择 的单号
          td.filedata = await this.convertFileToString(back_data[i]);        
          ok_data[i] = td;
        }
        
      }

      var j = 0;
      j = this.exist_data.length; 
      if (j > 0) {
        for (var i = 0; i < ok_data.length; i++) {
          this.exist_data[j] = ok_data[i];
          j += 1;
        }
        // 如果是多次拖放,需要进行二次整理
        var temp_d=[];
        for(var i=0;i<this.exist_data.length;i++){
          var temp_o={};
          temp_o.id = i + 1;
          temp_o.name = this.exist_data[i].name;
          temp_o.type = this.exist_data[i].type;
          temp_o.size = this.exist_data[i].size;
          temp_o.flag = this.exist_data[i].flag;
          temp_o.up = this.exist_data[i].up;
          temp_o.filedata= this.exist_data[i].filedata;
          temp_o.sheet_no= this.exist_data[i].sheet_no;
          temp_d[i]=temp_o;
        }
        this.pre_flies=temp_d;
      } else {
        this.exist_data = ok_data;
        this.pre_flies = this.exist_data;
      }
      if(this.pre_flies.length>0){
        this.show_tab = true;
      }

    },
    check_file_name:function(name){
      this.ok_name='';
      var chars = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];
      var maxLength = 6;
      var paramsAccount = '';
      for (var i = 0; i < maxLength; i++) {
          var id = Math.ceil(Math.random() * 35);
          paramsAccount += chars[id];
      }
      this.ok_name=paramsAccount+'_'+name;
      
    }  
  }
};


</script>


<style scoped>
.pre_upload {
  width: 100%;
  min-height: 200px;
  height: 100%;
  background-color: azure;
  text-align: center;
  /* padding: 10px 20px 10px 20px; */
}
.pre_leve_one {
  height: 5px;
}

.pre_leve_two {
  /* padding: 5px; */
  margin: 15px;
  margin-top: 15px;
  border: 1px solid #191970;
  min-height: 200px;
  height: auto;
}

.pre_files_data {
  width: 100%;
  min-height: 200px;
  height: auto;
  /* padding: 10px 20px 10px 20px; */
}

.pre_files_data > ul {
  list-style: none;
}
.pre_files_data > ul > li {
  border: 1px solid black;
}
.pre_files_data > ul > li > span {
  margin-left: 5px;
}

.pre_dataintable {
  margin-top: 15px;
  border-collapse: collapse;
  border: 1px solid #aaa;
  width: 95%;
  /* padding 没有作用 */
  /* padding: 0px 5px 10px 5px; */
  position: relative;
  left: 2%;
}
.pre_dataintable th {
  vertical-align: baseline;
  padding: 5px 15px 5px 6px;
  background-color: rgb(87, 201, 230);
  border: 1px solid #3f3f3f;
  text-align: left;
  color: #000000;
  font-size: 16px;
  font-weight: bolder;
}
.pre_dataintable td {
  vertical-align: text-top;
  padding: 6px 15px 6px 6px;
  border: 1px solid #aaa;
}
.pre_dataintable tr:nth-child(odd) {
  background-color: #f5f5f5;
}
.pre_dataintable tr:nth-child(even) {
  background-color: #fff;
}

.pre_tab_name {
  cursor: pointer;
  word-break: break-all;
}
.pre_tab_name:hover {
  cursor: pointer;
  background-color: #aaa;
}
/* 全部取消按钮 */
.pre_btn_del_all {
  color: black;
  font-size: 16px;
  width: 100px;
  height: 30px;
  background-color: rgba(236, 26, 26, 0.986);
}
/* 上传按钮 */
.pre_btn_up {
  color: black;
  font-size: 16px;
  width: 100px;
  height: 30px;
  background-color: rgba(44, 247, 61, 0.986);
}
/* 删除按钮 */
.pre_btn_canle {
  color: black;
  font-size: 16px;
  width: 80px;
  height: 25px;
  background-color: rgba(236, 26, 26, 0.986);
}
.pre_show_img {
  width: 400px;
  height: 400px;
  text-align: center;
  margin-top: -40px;
  /* background-color: #000000; */
}
.pre_show_img > img {
  width: auto;
  height: 100%;
}
</style>

 

870e5496ed969fcea41e0bd3d8965811ceb.jpg

转载于:https://my.oschina.net/qingqingdego/blog/3050322

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值