この記事では主に、シンプルで軽量なアップロード ファイル コンポーネントをカプセル化する Vue の例を紹介します。編集者が非常に優れていると考えたので、参考として共有します。エディターをフォローして一緒に見てみましょう
1. 以前に遭遇したいくつかの問題
既存の UI フレームワークを使用して実装するプロセスでは、プロジェクトにファイルをアップロードするための多くの要件があります。説明できないバグが常に存在することはわかっています。たとえば、特定のアップロード コンポーネントを使用する場合、明確に (:multiple="false") とマークされていますが、実際には、複数のファイルを選択することが可能であり、たとえば次の場合に限り、アップロード時に複数のファイルが送信されます。 (:file-list="fileList" が追加されています) ") 属性でアップロード リストを手動で制御したい場合、アップロード イベント this.refs.[upload (component ref)].submit() が機能せず、実行できません。伝わった。要するに、私はそれを実装する方法を理解するのが面倒なので、関数を使用していますが、それを使用することに固執すると、プロジェクトに多くの不要なロジックとスタイルコードが追加されます。 ...
私は以前プロジェクトに Vue を使用していました。ビュー フレームワークには、チーム内の補足として element-ui、zp-ui、および iview が含まれています。フレームワークは使いやすいですが、自分のプロジェクトでは使用できないことがよくあります。特に、デザイン担当者が作成したインターフェイスは、既存のフレームワークとは大きく異なり、ソースコードを変更すると非効率で、未知のバグが発生しやすいです。そのため、時間をかけてこのアップロード コンポーネントをカプセル化します。
2. コードと紹介
親コンポーネント
<template> <p class="content"> <label for="my-upload"> <span>上传</span> </label> <my-upload ref="myUpload" :file-list="fileList" action="/uploadPicture" :data="param" :on-change="onChange" :on-progress="uploadProgress" :on-success="uploadSuccess" :on-failed="uploadFailed" multiple :limit="5" :on-finished="onFinished"> </my-upload> <button @click="upload" class="btn btn-xs btn-primary">Upload</button> </p> </template> <script> import myUpload from './components/my-upload' export default { name: 'test', data(){ return { fileList: [],//上传文件列表,无论单选还是支持多选,文件都以列表格式保存 param: {param1: '', param2: '' },//携带参数列表 } }, methods: { onChange(fileList){//监听文件变化,增减文件时都会被子组件调用 this.fileList = [...fileList]; }, uploadSuccess(index, response){//某个文件上传成功都会执行该方法,index代表列表中第index个文件 console.log(index, response); }, upload(){//触发子组件的上传方法 this.$refs.myUpload.submit(); }, removeFile(index){//移除某文件 this.$refs.myUpload.remove(index); }, uploadProgress(index, progress){//上传进度,上传时会不断被触发,需要进度指示时会很有用 const{ percent } = progress; console.log(index, percent); }, uploadFailed(index, err){//某文件上传失败会执行,index代表列表中第index个文件 console.log(index, err); }, onFinished(result){//所有文件上传完毕后(无论成败)执行,result: { success: 成功数目, failed: 失败数目 } console.log(result); } }, components: { myUpload } } </script>
親コンポーネントは、アップロード結果を表示するときにインターフェイスが数値を直接操作できるようにするために、ビジネス関連のロジックを特別に追加しました。 . 値。すべてのメソッドに必要なわけではありません。必要に応じて使用します。
サブコンポーネント
<template> <p> <input style="display:none" @change="addFile" :multiple="multiple" type="file" :name="name" id="my-upload"/> </p> </template>
ファイルをアップロードします。HTML部分は単なるタグのペアです。複雑なのは好きではありません
<script> export default { name: 'my-upload', props: { name: String, action: { type: String, required: true }, fileList: { type: Array, default: [] }, data: Object, multiple: Boolean, limit: Number, onChange: Function, onBefore: Function, onProgress: Function, onSuccess: Function, onFailed: Function, onFinished: Function }, methods: {}//下文主要是methods的介绍,此处先省略 } </script>
これは、必要な属性値を定義しますここでメソッドを属性として渡すことも可能です。
私が書いたコンポーネントは、一般的なフレームワークによってリリースされたものほど完全かつ包括的ではありません。また、冒頭で述べた、バインドされたファイルリストをアップロードできないという問題を解決するために最善を尽くしたいと考えています。私の姿勢が間違っています) 私が遭遇したこの問題を取り除くために、アクションに加えて、親によって渡される必要がある属性としてもファイルリストを使用できるようにしたいと考えています。成分。 (親コンポーネントの属性名は「-」で接続されており、子コンポーネントpropのキャメルケース命名に対応しています)
3. メインアップロード機能
methods: { addFile, remove, submit, checkIfCanUpload }
合計メソッドの 4 つの方法、ファイルの追加、移動 ファイル、送信、テスト (アップロード前のテスト) に加えて、次のことを 1 つずつ説明します。
addFile({target: {files}}){//input标签触发onchange事件时,将文件加入待上传列表 for(let i = 0, l = files.length; i < l; i++){ files[i].url = URL.createObjectURL(files[i]);//创建blob地址,不然图片怎么展示? files[i].status = 'ready';//开始想给文件一个字段表示上传进行的步骤的,后面好像也没去用...... } let fileList = [...this.fileList]; if(this.multiple){//多选时,文件全部压如列表末尾 fileList = [...fileList, ...files]; let l = fileList.length; let limit = this.limit; if(limit && typeof limit === "number" && Math.ceil(limit) > 0 && l > limit){//有数目限制时,取后面limit个文件 limit = Math.ceil(limit); // limit = limit > 10 ? 10 : limit; fileList = fileList.slice(l - limit); } }else{//单选时,只取最后一个文件。注意这里没写成fileList = files;是因为files本身就有多个元素(比如选择文件时一下子框了一堆)时,也只要一个 fileList = [files[0]]; } this.onChange(fileList);//调用父组件方法,将列表缓存到上一级data中的fileList属性 },
2. ファイルの追加
これは簡単です。ファイルが親コンポーネントでフォークされる場合がある場合、インデックスを渡すだけです。remove(index){ let fileList = [...this.fileList]; if(fileList.length){ fileList.splice(index, 1); this.onChange(fileList); } },
submit(){ if(this.checkIfCanUpload()){ if(this.onProgress && typeof XMLHttpRequest !== 'undefined') this.xhrSubmit(); else this.fetchSubmit(); } },
fetchSubmit(){ let keys = Object.keys(this.data), values = Object.values(this.data), action = this.action; const promises = this.fileList.map(each => { each.status = "uploading"; let data = new FormData(); data.append(this.name || 'file', each); keys.forEach((one, index) => data.append(one, values[index])); return fetch(action, { method: 'POST', headers: { "Content-Type" : "application/x-www-form-urlencoded" }, body: data }).then(res => res.text()).then(res => JSON.parse(res));//这里res.text()是根据返回值类型使用的,应该视情况而定 }); Promise.all(promises).then(resArray => {//多线程同时开始,如果并发数有限制,可以使用同步的方式一个一个传,这里不再赘述。 let success = 0, failed = 0; resArray.forEach((res, index) => { if(res.code == 1){ success++; //统计上传成功的个数,由索引可以知道哪些成功了 this.onSuccess(index, res); }else if(res.code == 520){ //约定失败的返回值是520 failed++; //统计上传失败的个数,由索引可以知道哪些失败了 this.onFailed(index, res); } }); return { success, failed }; //上传结束,将结果传递到下文 }).then(this.onFinished); //把上传总结果返回 },
これを使用する場合、on-progress 属性が存在し、XMLHttpRequest オブジェクトにアクセスできる限り、リクエストはネイティブ メソッドを使用して送信されます。それ以外の場合、リクエストは fetch(.進行状況は表示されません)。
上記は私があなたのためにまとめたものです。
関連記事:
Ajaxフォーム非同期ファイルアップロードサンプルコードドロップダウンメニューのカスケード操作
Ajaxで州と市の3段階のカスケードを実現
以上がVue は、シンプルで軽量なアップロード ファイル コンポーネントの例をカプセル化します。の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。