如何实现自己的上传文件组件并在vue js中自定义?
How to implement my own upload file component and make it customizable in vue js?
我正在从事一个项目,该项目需要在很多地方实现具有不同样式的上传文件组件。我想创建高度可定制的组件,我可以轻松修改其设计,而且我不想重复自己,想将所有通用逻辑提取到一个地方。
此刻我有一个vue.js 2.2.2 版和bulma css 框架。我有这个组件的基本实现,只有一种设计可用。它支持代表当前上传状态的几种状态:
- 组件正在等待输入
- 上传开始
- 上传成功完成
- 上传失败
此组件还负责上传过程。
此时我的组件有很多职责:
1. 它知道如何处理状态:
<p v-if="isWaiting">
...
</p>
<div v-if="isLoading" class="is-loading">
<p class="title">{{currentPercent}} %</p>
</div>
...
data() { return {
currentStatus = Statuses.waiting
}}
computed: {
isWaiting() {
return this.currentStatus === Statuses.waiting;
},
...
}
- 它知道如何上传数据并计算当前已传输数据的百分比:
selectedFileChanged: async function(event) {
if (event.target.files.length === 0) return;
this.currentStatus = Statuses.uploading;
this.selectedFile = event.target.files[0];
const formData = new FormData();
formData.append("file", this.selectedFile);
try {
const result = (await axios.post("some url", formData, {
onUploadProgress: progress => {
const loaded = progress.loaded;
const total = progress.total;
this.currentPercent = Math.floor((loaded * 100) / total);
}
})).data;
this.currentStatus = Statuses.uploaded;
this.$emit("fileUploaded", {
file: this.selectedFile,
payload: result
});
} catch (exception) {
this.currentStatus = Statuses.error;
}
}
- 它只有一种样式我可以使用
您可以在此处找到完整代码:https://codesandbox.io/s/vue-template-gz2gk
所以我的问题是:如何构建此组件以便有机会轻松更改其样式以及如何处理上传状态?
在我看来:
1.组件应该不知道axios是什么以及如何上传数据;
2. 组件应该只负责当前状态以及如何显示
我可以介绍一个新的上传服务,它将知道如何上传数据并为上传文件组件添加一个新的道具(当前状态)并从父组件更改它。但在这种情况下,我将为组件的所有实例编写相同的代码。
有人知道如何创建此类可自定义组件的最佳实践吗?
更新 1
我尝试使用插槽实现此功能并最终得到:https://codesandbox.io/s/vue-template-pi7e9
组件仍然知道如何上传数据,但现在我可以更改上传组件的样式。
所以新的问题是:如何使用插槽而不传输大量变量以及如何处理上传。我不想让我的组件知道如何上传数据:(
我已经按照以下方式完成了组件:
在我的父组件中,我的组件有两种不同的样式:
<div id="app" class="container box">
<upload-file url="url"></upload-file> <-- the default one with statuses outside -->
<upload-file url="url"> <-- custom one which look like a box with statuses in it -->
<template #fileselect="{status, change}">
<custom-file-upload :status="status" @change="change"></custom-file-upload>
</template> <-- I've used custom-file-upload component here and tnjected all the properties from default implementation -->
</upload-file>
</div>
我的默认文件输入只是一个带有默认实现的插槽:
<template>
<div>
<slot name="fileselect" :change="selectedFileChanged" :status="status">
<input id="fileselect" @change="selectedFileChanged" class="file-input" type="file">
<div class="help is-info" v-if="isWaiting">Waiting</div>
<div class="help is-success" v-if="isUploaded">Uploaded</div>
<div class="help is-info" v-if="isUploading">Uploading {{currentPercent}} %</div>
<div class="help is-error" v-if="isFailed">Failed</div>
</slot>
</div>
</template>
代码是什么样的:
name: "upload-file",
props: ["url"], // url which will be used in upload request
data() {
return {
currentStatus: 1,
selectedFile: null,
currentPercent: 0
};
},
computed: {
someOtherProperties,
status() {
return {
isWaiting: this.isWaiting, // this.currentStatus === 1
isUploaded: this.isUploaded,
isUploading: this.isUploading,
isFailed: this.isFailed,
currentPercent: this.currentPercent,
selectedFile: this.selectedFile
};
}
},
methods: {
selectedFileChanged: function(event) {
this.selectedFile = event.target.files[0];
const xhr = new XMLHttpRequest();
// some handlers for XHR
xhr.open("POST", this.url, true);
xhr.send(formData);
}
}
现在我可以使用具有不同样式的文件上传组件,但它会将所有状态处理和上传逻辑封装在一个基本实现中。
我希望这个解决方案对某人有所帮助:)
查看完整版代码,请关注https://codesandbox.io/s/vue-template-pi7e9
我正在从事一个项目,该项目需要在很多地方实现具有不同样式的上传文件组件。我想创建高度可定制的组件,我可以轻松修改其设计,而且我不想重复自己,想将所有通用逻辑提取到一个地方。
此刻我有一个vue.js 2.2.2 版和bulma css 框架。我有这个组件的基本实现,只有一种设计可用。它支持代表当前上传状态的几种状态:
- 组件正在等待输入
- 上传开始
- 上传成功完成
- 上传失败
此组件还负责上传过程。
此时我的组件有很多职责: 1. 它知道如何处理状态:
<p v-if="isWaiting">
...
</p>
<div v-if="isLoading" class="is-loading">
<p class="title">{{currentPercent}} %</p>
</div>
...
data() { return {
currentStatus = Statuses.waiting
}}
computed: {
isWaiting() {
return this.currentStatus === Statuses.waiting;
},
...
}
- 它知道如何上传数据并计算当前已传输数据的百分比:
selectedFileChanged: async function(event) {
if (event.target.files.length === 0) return;
this.currentStatus = Statuses.uploading;
this.selectedFile = event.target.files[0];
const formData = new FormData();
formData.append("file", this.selectedFile);
try {
const result = (await axios.post("some url", formData, {
onUploadProgress: progress => {
const loaded = progress.loaded;
const total = progress.total;
this.currentPercent = Math.floor((loaded * 100) / total);
}
})).data;
this.currentStatus = Statuses.uploaded;
this.$emit("fileUploaded", {
file: this.selectedFile,
payload: result
});
} catch (exception) {
this.currentStatus = Statuses.error;
}
}
- 它只有一种样式我可以使用
您可以在此处找到完整代码:https://codesandbox.io/s/vue-template-gz2gk
所以我的问题是:如何构建此组件以便有机会轻松更改其样式以及如何处理上传状态?
在我看来: 1.组件应该不知道axios是什么以及如何上传数据; 2. 组件应该只负责当前状态以及如何显示
我可以介绍一个新的上传服务,它将知道如何上传数据并为上传文件组件添加一个新的道具(当前状态)并从父组件更改它。但在这种情况下,我将为组件的所有实例编写相同的代码。
有人知道如何创建此类可自定义组件的最佳实践吗?
更新 1 我尝试使用插槽实现此功能并最终得到:https://codesandbox.io/s/vue-template-pi7e9
组件仍然知道如何上传数据,但现在我可以更改上传组件的样式。 所以新的问题是:如何使用插槽而不传输大量变量以及如何处理上传。我不想让我的组件知道如何上传数据:(
我已经按照以下方式完成了组件:
在我的父组件中,我的组件有两种不同的样式:
<div id="app" class="container box">
<upload-file url="url"></upload-file> <-- the default one with statuses outside -->
<upload-file url="url"> <-- custom one which look like a box with statuses in it -->
<template #fileselect="{status, change}">
<custom-file-upload :status="status" @change="change"></custom-file-upload>
</template> <-- I've used custom-file-upload component here and tnjected all the properties from default implementation -->
</upload-file>
</div>
我的默认文件输入只是一个带有默认实现的插槽:
<template>
<div>
<slot name="fileselect" :change="selectedFileChanged" :status="status">
<input id="fileselect" @change="selectedFileChanged" class="file-input" type="file">
<div class="help is-info" v-if="isWaiting">Waiting</div>
<div class="help is-success" v-if="isUploaded">Uploaded</div>
<div class="help is-info" v-if="isUploading">Uploading {{currentPercent}} %</div>
<div class="help is-error" v-if="isFailed">Failed</div>
</slot>
</div>
</template>
代码是什么样的:
name: "upload-file",
props: ["url"], // url which will be used in upload request
data() {
return {
currentStatus: 1,
selectedFile: null,
currentPercent: 0
};
},
computed: {
someOtherProperties,
status() {
return {
isWaiting: this.isWaiting, // this.currentStatus === 1
isUploaded: this.isUploaded,
isUploading: this.isUploading,
isFailed: this.isFailed,
currentPercent: this.currentPercent,
selectedFile: this.selectedFile
};
}
},
methods: {
selectedFileChanged: function(event) {
this.selectedFile = event.target.files[0];
const xhr = new XMLHttpRequest();
// some handlers for XHR
xhr.open("POST", this.url, true);
xhr.send(formData);
}
}
现在我可以使用具有不同样式的文件上传组件,但它会将所有状态处理和上传逻辑封装在一个基本实现中。
我希望这个解决方案对某人有所帮助:)
查看完整版代码,请关注https://codesandbox.io/s/vue-template-pi7e9