• Vue3中图片上传组件封装-element-plus的el-upload二次封装-案例


     代码封装 

    1. <div class="form-box-item">
    2. <div class="form-box-item-label">交易盈利证明div>
    3. <el-upload
    4. v-if="!ImageProve"
    5. class="upload-box"
    6. ref="uploadRef"
    7. drag
    8. multiple
    9. action=""
    10. :limit="1"
    11. :auto-upload="false"
    12. :http-request="uploadBpmn"
    13. :before-upload="(file) => beforeUpload(file)"
    14. :on-change="handleChange"
    15. :on-error="handError"
    16. >
    17. <img src="@/assets/images/futures/upload.png" alt="" />
    18. <div class="el-upload__text">
    19. <div class="upload-green-text">上传文件div>
    20. <div class="upload-text">或拖拽放入div>
    21. div>
    22. el-upload>
    23. <img v-else style="width: 150px" :src="ImageProve" />
    24. div>
    1. const uploadRef = ref(null);
    2. const fileType = ref({
    3. limitSize: 2,
    4. type: 'png'
    5. });
    6. const beforeUpload = (file) => {
    7. console.log('beforeUpload', file);
    8. // 上传文件之前钩子
    9. const type = file.name.split('.')[file.name.split('.').length - 1];
    10. console.log(type, '文件格式!');
    11. if (file && file.size / 1024 / 1024 > fileType.value.limitSize) {
    12. ElMessage.error(`文件大小不能超过${fileType.value.limitSize}`);
    13. return false;
    14. }
    15. if (file && !fileType.value.type.indexOf(file.type) == -1) {
    16. ElMessage.error(`只能上传${fileType.value.type}类型的文件`);
    17. return false;
    18. }
    19. };
    20. const uploadBpmn = (param) => {
    21. console.log('uploadBpmn', param);
    22. // const formData = new FormData();
    23. // formData.append('file', param.file);
    24. // console.log(formData.get('file'), param, 888);
    25. };
    26. const handleChange = (response, file, fileList) => {
    27. console.log('handleChange', response, file, fileList);
    28. // getProfileAvatarUploadParam(response);
    29. // console.log(uploadRef.value, 99);
    30. uploadRef.value.clearFiles(); //清除文件对象
    31. // uploadRef.value.submit() //提交 .clearFiles()清除
    32. };
    33. const handError = (error, file, fileList) => {
    34. console.log('handError', error, file, fileList);
    35. };
    36. // 获取头像上传参数
    37. const getProfileAvatarUploadParam = async (file) => {
    38. try {
    39. let params = {
    40. contentType: file.raw.type || 'image/png'
    41. };
    42. const {
    43. data: { data }
    44. } = await profileAvatarUploadParam(params);
    45. console.log('getProfileAvatarUploadParam', data);
    46. uploadImage(data, file);
    47. } catch (error) {
    48. console.log('getProfileAvatarUploadParam', error);
    49. }
    50. };
    51. const ImageProve = ref(null);
    52. // 上传图片
    53. const uploadImage = async (xhrData, file) => {
    54. console.log('uploadImage', xhrData, file);
    55. try {
    56. const formData = new FormData();
    57. for (const key in xhrData.param) {
    58. const value = xhrData.param[key];
    59. formData.append(key, value);
    60. }
    61. formData.append('file', file.raw);
    62. // console.log(xhrData.param, formData.get('file'), 9898);
    63. let config = {
    64. method: 'post',
    65. // maxBodyLength: Infinity,
    66. url: xhrData.uploadUrl,
    67. data: formData,
    68. headers: {
    69. 'Content-Type': 'multipart/form-data'
    70. }
    71. };
    72. const res = await axios.request(config);
    73. ImageProve.value = xhrData.accessUrl;
    74. console.log('uploadImage', res);
    75. } catch (error) {
    76. console.log('uploadImage', error);
    77. }
    78. };

    在Vue3中,我们可以使用element-plus提供的el-upload组件进行图片上传。但是有时候我们需要根据具体业务需求对该组件进行二次封装,以适应项目中的具体场景。下面给出一个基于element-plus的el-upload组件的二次封装,实现图片上传和图片预览功能。

    1. 安装element-plus

    Vue3项目中,我们可以使用npm或yarn来安装element-plus组件库。

    1. // 使用npm安装element-plus
    2. npm install element-plus --save
    3. // 使用yarn安装element-plus
    4. yarn add element-plus

    2. 封装图片上传组件

    在封装图片上传组件时,我们可以将el-upload组件进行二次封装,以方便在项目中的使用。具体封装代码如下:

    1. <script>
    2. export default {
    3. name: 'AvatarUploader',
    4. props: {
    5. actionUrl: {
    6. type: String,
    7. default: ''
    8. },
    9. showFileList: {
    10. type: Boolean,
    11. default: true
    12. },
    13. multiple: {
    14. type: Boolean,
    15. default: false
    16. },
    17. limit: {
    18. type: Number,
    19. default: 1
    20. },
    21. tip: {
    22. type: String,
    23. default: '只能上传jpg/png文件,且不超过2M'
    24. },
    25. fileList: {
    26. type: Array,
    27. default() {
    28. return [];
    29. }
    30. }
    31. },
    32. methods: {
    33. handleExceed(files, fileList) {
    34. this.$message.warning(`只能上传${this.limit}个文件`);
    35. },
    36. handleSuccess(response, file, fileList) {
    37. console.log(response, file, fileList);
    38. this.$emit('success', response, file, fileList);
    39. },
    40. beforeRemove(file, fileList) {
    41. return this.$confirm(`确定移除 ${file.name}?`);
    42. },
    43. handleRemove(file, fileList) {
    44. console.log(file, fileList);
    45. this.$emit('remove', file, fileList);
    46. },
    47. handlePreview(file) {
    48. window.open(file.url, '_blank');
    49. }
    50. }
    51. };
    52. script>
    53. <style scoped>
    54. .avatar-uploader {
    55. display: inline-block;
    56. width: 100px;
    57. height: 100px;
    58. border-radius: 50%;
    59. background-size: cover;
    60. background-position: center center;
    61. overflow: hidden;
    62. position: relative;
    63. }
    64. .avatar-uploader input {
    65. display: none;
    66. }
    67. .avatar-uploader-icon {
    68. display: block;
    69. width: 100%;
    70. height: 100%;
    71. line-height: 100px;
    72. text-align: center;
    73. font-size: 28px;
    74. color: #999;
    75. background-color: #fff;
    76. cursor: pointer;
    77. }
    78. .el-upload__tip {
    79. font-size: 12px;
    80. color: #999;
    81. margin-top: 10px;
    82. text-align: center;
    83. }
    84. style>

    在该封装组件中,我们定义了一些props属性,包括文件上传地址(actionUrl)、是否显示文件列表(showFileList)、是否支持多选(multiple)、最大上传文件个数(limit)、上传提示内容(tip)、文件列表(fileList)等。我们还定义了一些方法,包括文件数量超限(handleExceed)、文件上传成功(handleSuccess)、文件删除前(beforeRemove)、文件删除成功(handleRemove)、文件预览(handlePreview)等。在该封装组件中,我们使用了element-plus提供的el-upload组件,并在其基础上进行了二次封装。

    3. 使用封装组件

    在项目中使用我们封装好的图片上传组件非常简单,只需要在具体页面中引入该组件并传递相应的props属性即可。具体代码如下:

    1. <script>
    2. import AvatarUploader from '@/components/AvatarUploader.vue';
    3. export default {
    4. name: 'ImageUploadPage',
    5. components: {
    6. AvatarUploader
    7. },
    8. data() {
    9. return {
    10. uploadUrl: '',
    11. uploadTip: '只能上传jpg/png文件,且不超过2M',
    12. fileList: []
    13. };
    14. },
    15. methods: {
    16. handleSuccess(response, file, fileList) {
    17. console.log(response, file, fileList);
    18. },
    19. handleRemove(file, fileList) {
    20. console.log(file, fileList);
    21. }
    22. }
    23. };
    24. script>
    25. <style scoped>
    26. .upload-wrapper {
    27. width: 500px;
    28. margin: 0 auto;
    29. }
    30. style>

    在上述代码中,我们在ImageUploadPage页面中引入了我们封装好的AvatarUploader组件,并传递了相应的props属性。在实际使用中,我们可以根据具体业务需求进行修改和调整。


    Vue3中可以通过对element-plus的el-upload进行二次封装来实现图片上传组件的封装。下面是一份简单的示例:

    1、安装element-plus:

    npm install element-plus --save
    

    2、创建一个Upload.vue组件,并引入element-plus和相关样式:

    1. <template>
    2. <el-upload
    3. class="upload-demo"
    4. drag
    5. :headers="headers"
    6. :action="action"
    7. :multiple="multiple"
    8. :data="data"
    9. :before-upload="beforeUpload"
    10. :on-success="onSuccess"
    11. :on-error="onError"
    12. :on-exceed="handleExceed"
    13. :limit="limit"
    14. :show-file-list="showFileList"
    15. :file-list="fileList">
    16. <slot name="uploadButton">slot>
    17. <slot name="tip">slot>
    18. el-upload>
    19. template>
    20. <script>
    21. import { ref } from 'vue'
    22. import 'element-plus/packages/theme-chalk/src/base.scss'
    23. import 'element-plus/packages/theme-chalk/src/upload.scss'
    24. import {
    25. ElUpload,
    26. ElButton,
    27. ElPopover,
    28. } from 'element-plus'
    29. export default {
    30. components: {
    31. ElUpload,
    32. ElButton,
    33. ElPopover,
    34. },
    35. props: {
    36. action: {
    37. type: String,
    38. required: true,
    39. },
    40. headers: {
    41. type: Object,
    42. default: () => ({}),
    43. },
    44. multiple: {
    45. type: Boolean,
    46. default: false,
    47. },
    48. data: {
    49. type: Object,
    50. default: () => ({}),
    51. },
    52. limit: {
    53. type: Number,
    54. default: 0,
    55. },
    56. showFileList: {
    57. type: Boolean,
    58. default: true,
    59. },
    60. },
    61. emits: ['success', 'error'],
    62. setup(props, { emit }) {
    63. const fileList = ref([])
    64. const beforeUpload = (file) => {
    65. const isJPG = file.type === 'image/jpeg'
    66. const isGIF = file.type === 'image/gif'
    67. const isPNG = file.type === 'image/png'
    68. const isLt2M = file.size / 1024 / 1024 < 2
    69. if (!isJPG && !isGIF && !isPNG) {
    70. this.$message.error('上传图片只能是 JPG/GIF/PNG 格式!')
    71. return false
    72. }
    73. if (!isLt2M) {
    74. this.$message.error('上传图片大小不能超过 2MB!')
    75. return false
    76. }
    77. return true
    78. }
    79. const handleExceed = (files, fileList) => {
    80. this.$message.warning(`当前限制选择 ${props.limit} 张图片,本次选择了 ${files.length} 张,共选择了 ${files.length + fileList.length} 张。`)
    81. }
    82. const onSuccess = (response, file, fileList) => {
    83. emit('success', response, file, fileList)
    84. }
    85. const onError = (err, file, fileList) => {
    86. emit('error', err, file, fileList)
    87. }
    88. return {
    89. fileList,
    90. beforeUpload,
    91. handleExceed,
    92. onSuccess,
    93. onError,
    94. }
    95. },
    96. }
    97. script>
    98. <style scoped>
    99. .upload-demo {
    100. margin-top: 10px;
    101. display: flex;
    102. flex-wrap: wrap;
    103. justify-content: flex-start;
    104. align-items: center;
    105. }
    106. .upload-demo .el-upload {
    107. margin-right: 15px;
    108. margin-bottom: 15px;
    109. }
    110. .upload-demo .el-upload__tip {
    111. margin: 0;
    112. }
    113. .upload-demo .el-upload-list {
    114. margin: 0;
    115. }
    116. style>

    3、在父级组件中使用Upload.vue组件:

    1. <template>
    2. <div class="page">
    3. <upload
    4. :action="uploadUrl"
    5. :show-file-list="false"
    6. :limit="limit"
    7. @success="handleSuccess"
    8. @error="handleError"
    9. >
    10. <el-button size="small" type="primary">上传文件el-button>
    11. <el-popover
    12. slot="tip"
    13. placement="top"
    14. :width="tipWidth"
    15. trigger="hover"
    16. >
    17. <el-image
    18. style="width: 100%;"
    19. :src="tipImage"
    20. @error="handleTipImageError"
    21. />
    22. el-popover>
    23. upload>
    24. <el-upload-list :list-type="listType" :items="fileList" />
    25. div>
    26. template>
    27. <script>
    28. import Upload from '@/components/Upload.vue'
    29. import { ref } from 'vue'
    30. import { ElUploadList, ElButton, ElImage } from 'element-plus'
    31. import 'element-plus/packages/theme-chalk/src/base.scss'
    32. import 'element-plus/packages/theme-chalk/src/upload.scss'
    33. export default {
    34. components: {
    35. Upload,
    36. ElUploadList,
    37. ElButton,
    38. ElImage,
    39. },
    40. setup() {
    41. const fileList = ref([])
    42. const limit = 5
    43. const listType = 'picture-card'
    44. const uploadUrl = 'https://jsonplaceholder.typicode.com/posts/'
    45. const handleSuccess = (response, file, fileList) => {
    46. fileList.push({
    47. name: file.name,
    48. url: URL.createObjectURL(file.raw),
    49. })
    50. }
    51. const handleError = (err, file, fileList) => {
    52. console.error(err)
    53. }
    54. return {
    55. fileList,
    56. limit,
    57. listType,
    58. uploadUrl,
    59. handleSuccess,
    60. handleError,
    61. }
    62. },
    63. }
    64. script>
    65. <style scoped>
    66. .page {
    67. max-width: 640px;
    68. margin: 0 auto;
    69. }
    70. style>

    通过以上代码示例可以看出,在Upload.vue组件中,我们可以通过props来接收父组件传递的参数,比如上传地址(action)、上传时携带的参数(data)、上传的文件头信息(headers)等等。在父组件中,我们通过使用Upload.vue组件,并将需要上传的参数作为props传递给上传组件,同时也可以在Upload.vue组件中使用自定义事件来向父组件派发成功或错误的事件,比如上传成功事件(success)和上传错误事件(error)等等。在父组件中,我们可以通过设置listType属性来控制文件列表的显示方式,比如图片卡片显示方式(picture-card)或文件列表方式(text)等等。


     Vue3中图片上传组件的二次封装可以使用Element Plus中的el-upload组件。el-upload组件是一个通用的上传组件,支持多文件上传、拖拽上传、图片裁剪等功能。以下是一个基于Element Plus的el-upload组件的二次封装实例: