Filepond是我個(gè)人最喜歡的上傳組件之一,在功能全面的基礎(chǔ)上提供了額及其強(qiáng)大的可定制性以及最美觀的樣式。雖然官網(wǎng)有vue下的使用指南,但是并不是很全面。
在開發(fā)我的開源圖床框架PARA時(shí),我選擇了Filepond作為我的前端上傳插件。它具備官方的前端框架支持和幾乎所有你能想到的定制屬性。更棒的是,它在nuxt下依然非常好用。
基本使用
安裝:
npm install vue-filepond filepond --save
如果你和我一樣更喜歡yarn,那么命令為:
yarn add vue-filepond filepond
然后應(yīng)該就可以在vue中使用<file-pond>組件了,當(dāng)然這通常不夠。
掛載插件:
Filepond提供了很多插件,我通常會(huì)選擇可以預(yù)覽上傳圖片的ImagePreview和文件大小以及類型插件FileValidateType和FileValidateSize。插件要使用組件局部聲明的方式,掛載在filepond組件上。同時(shí)如果插件需要額外的css文件也需要提前引入,對(duì)于我的插件配置來說,代碼應(yīng)該像這樣:
//index.vue
import vueFilePond from "vue-filepond";
import "filepond/dist/filepond.min.css";
import 'filepond-plugin-image-preview/dist/filepond-plugin-image-preview.css';
import FilePondPluginImagePreview from 'filepond-plugin-image-preview';
import FilePondPluginFileValidateType from "filepond-plugin-file-validate-type";
import FilepondPluginFileValidateSize from "filepond-plugin-file-validate-size";
const FilePond = vueFilePond(
FilePondPluginFileValidateType,
FilepondPluginFileValidateSize,
FilePondPluginImagePreview
);
配置參數(shù)
官網(wǎng)的示例如下:
<template>
<div id="app">
<file-pond
name="test"
ref="pond"
class-name="my-pond"
label-idle="Drop files here..."
allow-multiple="true"
accepted-file-types="image/jpeg, image/png"
v-bind:files="myFiles"
v-on:init="handleFilePondInit"/>
</div>
</template>
<script>
// Import FilePond
import vueFilePond from 'vue-filepond';
// Import plugins
import FilePondPluginFileValidateType from 'filepond-plugin-file-validate-type/dist/filepond-plugin-file-validate-type.esm.js';
import FilePondPluginImagePreview from 'filepond-plugin-image-preview/dist/filepond-plugin-image-preview.esm.js';
// Import styles
import 'filepond/dist/filepond.min.css';
import 'filepond-plugin-image-preview/dist/filepond-plugin-image-preview.min.css';
// Create FilePond component
const FilePond = vueFilePond( FilePondPluginFileValidateType, FilePondPluginImagePreview );
export default {
name: 'app',
data: function() {
return { myFiles: ['index.html'] };
},
methods: {
handleFilePondInit: function() {
console.log('FilePond has initialized');
// example of instance method call on pond reference
this.$refs.pond.getFiles();
}
},
components: {
FilePond
}
};
</script>
如果只看官網(wǎng)的文檔,可定制的項(xiàng)似乎很少,但是根據(jù)在devtool中查看的結(jié)果,幾乎所有的定制項(xiàng)組件都有,所以直接在組件上設(shè)置就可以了。
坑:
其實(shí)我寫這篇文章主要是為了記錄這個(gè)樣式上的坑:
背景:
在框架中我設(shè)置的用戶權(quán)限組配置項(xiàng)有“是否可以多文件上傳這一項(xiàng)”,所以組件多文件上傳的開關(guān)是動(dòng)態(tài)綁定的。于此同時(shí)網(wǎng)站的首頁為了美觀設(shè)置了{(lán)height:100vh;overflow:hidden}來保證始終占據(jù)整屏且沒有滾動(dòng)欄。這就導(dǎo)致了如果用戶一次上傳了過多的文件,上傳列表將會(huì)超出屏幕。
官方解決方案:
為組件的根元素設(shè)置最大高度,當(dāng)設(shè)置了最大高度時(shí),如果超過了最大高度將會(huì)自動(dòng)顯示滾動(dòng)條:
.filepond--root {
max-height: 10em;
}
但是這也帶來了一個(gè)問題,因?yàn)楣俜皆谏山M件的時(shí)候,單文件上傳和多文件上傳的DOM結(jié)構(gòu)是不一樣的(可能官方以為只允許單文件上傳的時(shí)候開發(fā)者是想不到設(shè)置高度這碼事的)
問題:
單文件的組件邏輯為:將圖片拖入時(shí),有提示信息和“支撐元素高度”的label元素就會(huì)隱藏

我來抽象一下它的DOM樹:
<div class="filepond--wrapper">
<div class="filepond--root filepond--hopper" style="height: 76px;">
<input class="filepond--browser" type="file" accept="image/jpeg,image/png">
<div class="filepond--drop-label" style="transform: translate3d(0px, 0px, 0px); opacity: 1;">
<label aria-hidden="true">將文件拖入框中,或點(diǎn)擊<span class="filepond--label-action" tabindex="0">選擇</span></label></div>
<div class="filepond--list-scroller" style="transform: translate3d(0px, 0px, 0px);">
<ul class="filepond--list" role="list"></ul>
</div>
<div class="filepond--panel filepond--panel-root">
<div class="filepond--panel-top filepond--panel-root"></div>
<div class="filepond--panel-center filepond--panel-root"
style="transform: translate3d(0px, 8px, 0px) scale3d(1, 0.6, 1);"></div>
<div class="filepond--panel-bottom filepond--panel-root" style="transform: translate3d(0px, 68px, 0px);">
</div>
</div><span class="filepond--assistant" ></span>
<div class="filepond--drip"></div>
</div>
</div>
我刪去了一些和這個(gè)問題無關(guān)緊要的屬性,可以看出,我們?cè)O(shè)置最大高度的“filepond--root”元素它的高度是由一個(gè)內(nèi)聯(lián)的屬性決定的。而背景的灰色圓角邊框其實(shí)是絕對(duì)定位的“filepond-panel”元素所提供的。由top,center,bottom分別展示頂部圓角邊,中部,底部圓角邊。與此同時(shí),中部元素的css為:
.filepond--panel-center {
height: 100px !important;
border-top: none !important;
border-bottom: none !important;
border-radius: 0 !important;
}
但是如果我們對(duì)單文件上傳的組件設(shè)置最大高度,初始化組件的時(shí)候就會(huì)根據(jù)多文件組件的方式生成:

可以很直觀的看出,中間的元素高度缺失了。但其實(shí)元素和元素的高度還在,只是元素被隱藏了,造成隱藏的css樣式為:
.filepond--panel-center:not([style]) {
visibility: hidden;
}
這一原因?yàn)楫?dāng)多文件上傳時(shí),標(biāo)簽的dom是包含在panel內(nèi)的,這個(gè)時(shí)候panel的高度是真正的由標(biāo)簽占據(jù),此時(shí)標(biāo)簽是不消失的:

單文件版本標(biāo)簽消失:

所以如果是否允許多文件上傳的屬性是動(dòng)態(tài)綁定的,就不能把最大高度寫在CSS中!!!
解決方案:
如果不能把樣式固定在<style>中,而class綁定也不會(huì)生效(我試過,會(huì)被覆蓋),那么只能在組件的初始化上下功夫了,借助原生js直接修改樣式表:
//index.vue
<template>
...some code...
<Filepond @init="handlerInit" />
...some code...
</template>
<script>
...some code
export default{
mounted:{
if (allowMultiple) {
document.styleSheets[0].insertRule('.filepond--root {max-height: 60vh;}', 0);
}
}
}
</script>
即可達(dá)成想要的效果。
至于為什么會(huì)設(shè)置高度會(huì)導(dǎo)致DOM預(yù)設(shè)發(fā)生變化,仍在審計(jì)中.....