关于element-ui:elementUI中upload组件使用总结

63次阅读

共计 2754 个字符,预计需要花费 7 分钟才能阅读完成。

最近应用了 elementUI 提供的 upload 组件上传文件,总结下应用过程中的一些心得。本文不会介绍如何应用 elementUI 中的 upload 组件,因为官网自身就曾经介绍的很具体了。

本文次要包含以下几个问题:

  1. 文件校验是如何做的,是否同时校验多种文件格式;
  2. 上传文件的时候是否自定义拖拽款式;
  3. 点击的时候如何实现手动上传。

序言

  1. 本文波及到源码的局部,以 v2.15.1 为例;
  2. upload 组件源代码在 /packages/upload 文件夹上面;

文件校验是如何做的,是否同时校验多种文件格式

upload 组件提供了两种上传文件的形式:

  1. input 元素形式:通过 input 元素触发零碎的文件抉择窗口来抉择文件;
  2. 拖拽形式:通过原生 drag 和 drop API 来抉择文件。

针对上述两种形式,upload 组件提供了属性 accept限度 校验 文件格式。这里,我应用了两个词:

  1. 限度:从源头层面上限度,也就是不是特定的格局就抉择不了,实用于input 元素形式
  2. 校验:从后果层面上校验,也就是在最初一步能力发现抉择不了,同时实用于上述两种形式,其中校验又包含两种:

    1. 源码自身蕴含的校验逻辑;
    2. 自定义校验。

接下来咱们联合 upload 组件源码来剖析下实现原理。

限度

限度模式的次要原理就是原生 input 元素的 accept 属性(源码 /packages/upload/src/upload.vue 文件第 206 行):

<input class="el-upload__input" type="file" ref="input" name={name} on-change={handleChange} multiple={multiple} accept={accept}></input>

当没有增加 accept 属性的时候,零碎的文件抉择框中的文件都是可选的:

<input type="file" />

当增加了 accept 之后,比方.png,零碎的文件抉择框中只有合乎格局的文件才是可选的:

<input type="file" accept=".png" />

如何反对多种文件格式上传呢?看下原生 input 元素 accept 属性的文档,会发现 accept 是反对逗号宰割的多种文件格式的:

<input type="file" accept=".png,.jpg,.jpeg" />


开发的时候发现一个有意思的问题,就是如果 accept 外面.jpg 和.jpeg 只写一个,另外一种格局也是能够抉择的:

<input type="file" accept=".png,.jpeg" />
// 或者
<input type="file" accept=".png,.jpg" />


所以,jpg 和 jpeg 有啥关系?查找了下材料,发现这两种格局并没有任何区别,至于为什么会有两个名字,说是先有了 jpeg,而后 Windows 的晚期版本规定文件的扩展名只能是三个字符,所以就变成了 jpg。感兴趣的能够参考这篇文章。

所以,

  1. 只通过 accept 的模式限度文件类型有时候可能不精确;
  2. Windows 零碎可能会有兼容性问题,也就是即便提供了 accept 属性,其余格局的文件也是可选的;

这个时候就只能依赖上面的校验形式了。

源码自身蕴含的校验逻辑

当应用 拖拽形式 上传文件的时候,是能够拖拽任何文件的,所以只能在拖拽实现的时候去校验文件格局。那么,应该去校验哪些格局呢?从 upload 组件使用者的角度来说,无论是 input 元素形式 还是 拖拽形式,都应该是放弃对立的。也就是,原生 input 的 accept 属性反对的格局,在应用拖拽形式的时候,也都得反对。

所以,先看下 input 的 accept 属性反对的格局类型:

  1. 文件扩展名模式,以 . 结尾;
  2. MIME 类型;
  3. “audio/*” “video/*” “image/*”。

upload 组件源码针对上述三种类型做的相应解决(/packages/upload/src/upload-dragger.vue文件 onDrop 办法)如下:

this.$emit('file', [].slice.call(e.dataTransfer.files).filter(file => {const { type, name} = file;
  const extension = name.indexOf('.') > -1
    ? `.${name.split('.').pop()}`
    : '';
  const baseType = type.replace(/\/.*$/, '');
  return accept.split(',')
    .map(type => type.trim())
    .filter(type => type)
    .some(acceptedType => {if (/\..+$/.test(acceptedType)) { // 1. 扩展名模式
        return extension === acceptedType;
      }
      if (/\/\*$/.test(acceptedType)) { // 3. "audio/*" "video/*" "image/*"
        return baseType === acceptedType.replace(/\/\*$/, '');
      }
      if (/^[^\/]+\/[^\/]+$/.test(acceptedType)) { // 2. MIME 类型
        return type === acceptedType;
      }
      return false;
    });
}));

自定义校验

upload 组件提供了自定义校验的钩子函数:before-upload。依据该函数的返回值决定是持续还是终止(/packages/upload/src/upload.vue文件第 91 行):

const before = this.beforeUpload(rawFile);

上传文件的时候是否自定义拖拽款式

论断:不能

尝试

dragEvent 有一个 dataTransfer 属性,这个属性有一个 setDragImage 办法,该办法看似能够用来自定义拖拽款式。然而,这个办法有一个应用限度:只能在 dragstart 事件中调用。

然而当从操作系统拖拽文件到浏览器中的时候,dragstart 事件是不会触发的,所以 setDragImage 办法不能实现咱们的目标。

点击的时候如何实现手动上传

upload 组件 dom 中蕴含一个不显示的 input 元素,当点击组件的时候触发 input 元素的 click 事件(/packages/upload/src/upload.vue):

handleClick() {if (!this.disabled) {
    this.$refs.input.value = null;
    this.$refs.input.click();}
}

总结

如有谬误,欢送留言探讨。

参考资料

  1. file drag and drop API;
  2. upload 组件 GitHub 地址;
  3. jpg 和 jpeg 文件的区别。

正文完
 0