:基于 DropZone 與 FilePicker 的 ZIP 文件上傳區(qū)域)
wp-calypso Upload Drop Zone 組件實戰(zhàn)基于 DropZone 與 FilePicker 的 ZIP 文件上傳區(qū)域【免費下載鏈接】wp-calypsoThe JavaScript and API powered WordPress.com項目地址: https://gitcode.com/gh_mirrors/wp/wp-calypsoUpload Drop Zone 是 wp-calypso 中一個將“拖拽放置區(qū)drop-zone”與“文件選擇器file-picker”合二為一的復(fù)合組件專門用于上傳 ZIP 壓縮包用戶既可以點擊區(qū)域打開系統(tǒng)文件瀏覽器也可以直接把單個 zip 文件拖拽到區(qū)域上完成上傳。閱讀本文后你將掌握該組件的 Props 契約、內(nèi)部校驗與錯誤處理邏輯理解它如何復(fù)用 DropZone 與 FilePicker 兩個底層基礎(chǔ)組件并能參照 主題上傳頁面 的真實集成方式在自己的業(yè)務(wù)界面中落地使用。組件定位拖拽與點擊二合一的上傳入口組件源碼位于 client/blocks/upload-drop-zone由三個文件組成index.jsx組件實現(xiàn)、style.scss樣式、README.md文檔。按官方 README 的定義A combined drop-zone and filepicker for uploading zip files. Click to open a file browser, or drop a single zip file onto it. Accepts a function that will be called with the selected file.它的核心定位可以拆解為三點一種交互、兩種入口點擊區(qū)域彈出文件選擇器或?qū)⑽募献У絽^(qū)域上最終走同一條doUpload回調(diào)面向 ZIP 場景文件選擇器通過acceptapplication/zip限定可選類型并提示“Only single .zip files are accepted.”單個文件約束內(nèi)部強制只接受單個 zip 文件多文件、超大文件都會被攔截并給出錯誤提示。快速上手最小接入示例按照 README 提供的用法接入方式非常簡潔——只需要向組件傳入一個處理上傳的函數(shù)function render() { const doUpload this.props.uploadTheme; return UploadDropZone doUpload{ doUpload } /; }從源碼實現(xiàn)看doUpload的實際簽名是doUpload( siteId, file )其中siteId由組件內(nèi)部通過 Redux 自動注入詳見下文 Props 說明業(yè)務(wù)方只需關(guān)注拿到File對象后如何處理即可。Props 契約詳解doUpload必需屬性值TypeFunctionRequiredYes在 index.jsx 中doUpload被聲明為PropTypes.func.isRequired。README 明確說明它接收siteId和File兩個參數(shù)當(dāng)用戶選中拖入或點選一個 zip 文件后即被調(diào)用。disabled可選屬性值TypeBooleanRequiredNo設(shè)為true時禁用整個選擇器與放置區(qū)。禁用狀態(tài)在視覺上由 style.scss 通過is-disabled類實現(xiàn)opacity: 0.2降低透明度pointer-events: none阻斷所有鼠標(biāo)交互同時該狀態(tài)也會透傳給底層的DropZonedisabledprop使其不再響應(yīng)拖拽事件。源碼中暴露的額外 PropsREADME 未列出但可用onFileTooLargeFunction可選當(dāng)用戶選擇的文件超過大小上限時若提供了此回調(diào)則優(yōu)先調(diào)用它未提供時組件會自行彈出錯誤提示見下文“文件校驗”小節(jié)。siteIdnumber自動注入通過connect從getSelectedSiteId( state )獲取因此業(yè)務(wù)方通常不需要手動傳遞。交互流程與內(nèi)部實現(xiàn)剖析組件的完整交互鏈路在 index.jsx 中實現(xiàn)核心是onFileSelect處理器onFileSelect ( files ) { const { translate, siteId, doUpload } this.props; if ( files.length ! 1 ) { this.props.errorNotice( translate( Please drop a single zip file ) ); return; } // DropZone supplies an array, FilePicker supplies a FileList const file files[ 0 ] || files.item( 0 ); if ( file.size MAX_UPLOAD_ZIP_SIZE ) { if ( this.props.onFileTooLarge ) { this.props.onFileTooLarge(); } else { this.props.errorNotice( translate( Zip file is too large. Please upload a file under %(maxSize)d MB., { args: { maxSize: Math.floor( MAX_UPLOAD_ZIP_SIZE / 1000000 ) }, } ) ); } return; } doUpload( siteId, file ); };數(shù)據(jù)源歸一化這里有一個值得注意的兼容性細(xì)節(jié)DropZone的onFilesDrop回調(diào)傳遞的是數(shù)組而FilePicker的onPick回調(diào)傳遞的是FileList。組件用files[ 0 ] || files.item( 0 )同時兼容兩種數(shù)據(jù)結(jié)構(gòu)這也是onFileSelect能被兩個入口共用的前提。文件校驗數(shù)量校驗files.length ! 1時直接彈出“Please drop a single zip file”拒絕多文件上傳大小校驗MAX_UPLOAD_ZIP_SIZE定義于 client/lib/automated-transfer/constants.js值為50 * 1000000即50MB。超過上限時優(yōu)先觸發(fā)onFileTooLarge回調(diào)否則通過errorNotice展示“Zip file is too large. Please upload a file under 50 MB.”的錯誤提示。渲染結(jié)構(gòu)return ( div className{ className } div classNameupload-drop-zone__dropzone DropZone onFilesDrop{ this.onFileSelect } disabled{ disabled } / FilePicker acceptapplication/zip onPick{ this.onFileSelect } Gridicon classNameupload-drop-zone__icon iconcloud-upload size{ 48 } / { dropText } span classNameupload-drop-zone__instructions{ uploadInstructionsText }/span /FilePicker /div /div );界面文案由 i18n 翻譯函數(shù)生成主文案為“Drop files or click here to install”輔助說明為“Only single .zip files are accepted.”。整個上傳區(qū)塊由DropZone負(fù)責(zé)拖拽放置和FilePicker負(fù)責(zé)點擊選擇疊加構(gòu)成二者共享onFileSelect回調(diào)。底層基礎(chǔ)組件機制Upload Drop Zone 并非從零實現(xiàn)拖拽邏輯而是組合了兩個可復(fù)用的基礎(chǔ)組件理解它們有助于排查問題與二次開發(fā)。DropZone拖拽放置區(qū)client/components/drop-zone/index.jsx 是一個全局事件驅(qū)動的拖拽區(qū)域在componentDidMount中向window注冊dragover、drop、dragenter、dragleave、mouseup事件監(jiān)聽見 L44-L51并在卸載時逐一移除通過dragEnterNodes集合與MutationObserver追蹤拖拽目標(biāo)節(jié)點以判斷文件是否正在頁面上拖拽見 toggleMutationObserveronDrop中除了觸發(fā)onFilesDrop( Array.prototype.slice.call( event.dataTransfer.files ) )外還會preventDefault阻止瀏覽器默認(rèn)的“打開文件”行為并處理了 Safari 從 Dock 直接拖文件的兼容問題見 L163-L189支持fullScreen全屏放置模式此時通過RootChild渲染到根節(jié)點并允許通過CustomEvent重定向拖拽事件例如覆蓋在 iframe 上方的場景。FilePicker點擊打開文件選擇器client/components/file-picker/index.jsx 是一個輕量的點擊觸發(fā)組件其核心邏輯在 component-file-picker.js在頁面加載時預(yù)創(chuàng)建一個隱藏的form與input typefile見 L11-L16每次點擊調(diào)用input.click()彈出系統(tǒng)文件對話框并監(jiān)聽change事件把input.files通過onPick回傳支持multiple多選、directory選擇目錄、accept限定文件類型三個選項accept既支持字符串如application/zip也支持?jǐn)?shù)組拼接。Upload Drop Zone 使用它時傳入acceptapplication/zip從而在系統(tǒng)文件對話框中直接過濾出 zip 文件。樣式表現(xiàn)與交互反饋style.scss 定義了上傳區(qū)域的視覺形態(tài)默認(rèn)態(tài)position: relative的容器淺灰背景--color-neutral-0、2px 虛線邊框--color-neutral-light內(nèi)容區(qū)固定 180px 高度、垂直水平居中懸停態(tài)邊框加深、整體上移 1px 并帶輕微陰影云朵上傳圖標(biāo)cloud-upload48px同步變色給用戶“可交互”的反饋禁用態(tài)如上所述透明度降到 0.2 且阻斷事件。真實業(yè)務(wù)集成案例主題上傳頁Upload Drop Zone 在 wp-calypso 中的典型消費者是主題上傳頁面 client/my-sites/themes/theme-upload/index.jsx其接入方式可作為業(yè)務(wù)方的最佳實踐模板按需加載通過AsyncLoad配合 webpack 動態(tài)importwebpackChunkName: async-load-calypso-blocks-upload-drop-zone延遲加載組件避免拖慢首屏見 L79-L82差異化上傳策略doUpload根據(jù)站點類型分發(fā)——Jetpack 站點調(diào)用uploadTheme( siteId, file )非 Jetpack 站點調(diào)用initiateThemeTransfer( siteId, file, , , theme_upload )見 L292-L295權(quán)限與狀態(tài)聯(lián)動disabled由canUploadThemesOrPlugins站點是否具備FEATURE_UPLOAD_THEMES/FEATURE_UPLOAD_PLUGINS特性與自動化轉(zhuǎn)移資格共同決定上傳期間切換為進(jìn)度條組件ThemeUploadProgress上傳完成后展示主題信息卡片。這一集成方式清晰展示了doUpload回調(diào)與disabled屬性的實際使用語境業(yè)務(wù)方負(fù)責(zé)一切與站點、權(quán)限、上傳協(xié)議相關(guān)的邏輯Upload Drop Zone 只專注于“收集一個合法的 zip 文件并交給回調(diào)”。小結(jié)Upload Drop Zone 是 wp-calypso 中一個職責(zé)劃分清晰的復(fù)合組件它通過組合DropZone與FilePicker把“拖拽”與“點選”兩種上傳入口收斂為統(tǒng)一的doUpload( siteId, file )回調(diào)并在內(nèi)部完成單文件、類型與 50MB 大小限制的校驗。無論是參考 README 快速接入還是閱讀 index.jsx 理解校驗鏈路抑或參照 主題上傳頁 做權(quán)限、狀態(tài)與上傳協(xié)議的完整集成你都可以在本文的基礎(chǔ)上直接進(jìn)入實戰(zhàn)。【免費下載鏈接】wp-calypsoThe JavaScript and API powered WordPress.com項目地址: https://gitcode.com/gh_mirrors/wp/wp-calypso創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考