上传自定义模板,上传成功和失败状态的自定义模板用不了

来源:9-5 Uploader 组件第三部分:自定义模版

qq_稻草人_81

2021-05-03

这里是上传组件:

<template>
  <div class="file-upload">
      <div class="file-upload-container" @click.prevent="triggerUpload">
          <slot v-if="fileStatus === 'loading'" name="loading">
              <button class="btn btn-primary" disabled>正在上传...</button>
          </slot>
          <solt v-else-if="fileStatus === 'sucess'" name='uploaded' :uploadData="uploadData">
              <button class="btn btn-primary">上传成功</button>
          </solt>
          <solt v-else-if="fileStatus === 'error'" name='error'>
              <button class="btn btn-primary" >上传失败</button>
          </solt>
         
          <slot v-else name="default">
              <button class="btn btn-primary">上传文件</button>
          </slot>
          </div>
      <input type="file"
       class="file-input d-none"
       ref="fileInput"
       @change="handleFileChange">
  </div>
</template>

<script lang='ts'>
/* 上传文件,自定义模板 */
import {defineComponent,ref,PropType} from 'vue'

import axios from '@/api/request'

// 定义上传的状态
type UploaderStatus = 'ready' | 'loading' | 'sucess' | 'error'

// 自定义检查,是一个函数,返回的是布尔值
type checkFunction = (file: File) => boolean

export default defineComponent({
props: {
    action: {
        type:String,
        required: true
    },
    /* 上传前的一系列检查 */
    boforeUpload: {
        type: Function as PropType<checkFunction>
    }
},
// 定义要暴露的上传成功事件,上传失败事件
emits: ['file-uploaded','file-uploaded-error'],
setup(props,context){

    // 绑定ref,获得input元素的节点
    const fileInput = ref<null | HTMLInputElement>(null)

    // 定义返回出去的数据
    const uploadData = ref()

    
    // 创建上传状态的响应式对象
    const fileStatus = ref<UploaderStatus>('ready')

    const triggerUpload  = () => {
        //当input节点存在的时候,就触发点击事件
        if (fileInput.value) {
           fileInput.value.click() 
        }
    }

    // input 的change事件
    const handleFileChange = ((e:Event) => {
        // 获取里面的文件,这样是为了获得file属性
        const currentTarget = e.target as HTMLInputElement
        // 如果条件为真,说明已经选择了文件,可以上传
        if (currentTarget.files) {
            // 因为currentTarget.files不是一个数组,需要手动转换
            const fiels = Array.from(currentTarget.files)

            // 如果存在该属性,就做上传前的一系列检查
            if (props.boforeUpload) {
                const result = props.boforeUpload(fiels[0])

                // 如果不满足条件,就不执行下面的程序
                if (!result) {
                    return
                }
            }
            fileStatus.value = 'loading'
            const formData = new FormData
            formData.append('file',fiels[0])
            axios.post(props.action ,formData,{
                headers: {
                    'Content-Type': 'multipart/form-data'
                }
            }).then(res => {
                fileStatus.value = 'sucess'
                // 上传成功后,暴露成功事件
                uploadData.value = res.data
                context.emit('file-uploaded',res.data)
                
            }).catch(err => {
                fileStatus.value = 'error'
                context.emit('file-uploaded-error',{err})
            }).finally(() => {
                if (fileInput.value) {
                    fileInput.value.value = ''
                }
            })

        }
    })


    return {
        fileInput,
        triggerUpload,
        handleFileChange,
        fileStatus,
        uploadData
    }
}
})
</script>

<style>

</style>

这里是使用上传组件的页面:

<template>
  <div>
    <Uploader action="/upload" 
    :boforeUpload="boforeUpload" 
    @file-uploaded="onFileUploaded"
    @file-uploaded-error="onfileUploadedError">
     <template #loading>
     <span>正在上传中。。。</span>
     </template>
     
    </Uploader>
      <column-list :list="testData"></column-list>
  </div>
</template>

<script lang='ts'>
/* 使用上传文件,自定义模板 */
import {defineComponent,computed,onMounted} from 'vue'
import ColumnList from '@/components/ColumnList/ColumnList.vue'

import {useStore} from 'vuex'
import {GlobalDataProps,ResponseType,ImageProps} from '@/store/index'

import Uploader from '@/components/Uploader/Uploader.vue'

import createMessage from '@/hooks/createMessage'

export default defineComponent({
  components: {
    ColumnList,
    Uploader
  },
  setup(){
    // 为了能够更好的提示,我们这里使用泛型
    const store = useStore<GlobalDataProps>()

    onMounted(() => {
      // 经过此方式,把请求到的数据赋值给columns
      store.dispatch('fetchColumns')
    })
   // 然后
    const list = computed(()=>  store.state.columns)

    // 做上传前的一系列检查
    const boforeUpload = (file:File) => {
      const isPng = file.type == 'image/png'
      if (!isPng) {
        createMessage('上传文件格式不是png','error')
      }
      return isPng
    }

    // 上传成功
    const onFileUploaded = (rawData:ResponseType<ImageProps>) => {
      console.log('上传成功了:',rawData);
      
      createMessage(`上传图片ID ${rawData.data._id}`,'success')
    }
    // 上传失败
    const onfileUploadedError = (err:ResponseType<ImageProps>) => {
      console.log('err',err);
      const msg = err.msg || '上传路径错误'
      createMessage(`上传文件 ${msg}`,'error')
      
    }
    return {
      testData:list,
      boforeUpload,
      onFileUploaded,
      onfileUploadedError
    }
  }
})
</script>

<style>

</style>

在使用上传组件的页面,只有状态为ready和loading自定义模板才生效,上传状态为成功和失败却不行,不知道哪里出现了问题?

写回答

3回答

张轩

2021-05-05

同学你好 找到问题了 你的拼写错误了~ 下次请细心一点~

// uploader.vue 第七行
<slot> 你拼写成了 <solt>
第十行的问题是一样的


0
1
qq_稻草人_81
好家伙,太粗心了,原来bug在这里,谢谢老师
2021-05-05
共1条回复

张轩

2021-05-05

同学你好 我下载使用了 发现这个问题已经解决了是吗?

0
1
qq_稻草人_81
还没有解决,卡一天了,默认插槽和上传中状态的插槽可以用,成功后的状态和失败的状态却不行
2021-05-05
共1条回复

张轩

2021-05-04

同学你好 能否辛苦你提供一下源代码吗?(git) 我在本地帮你看一下

0
3
qq_稻草人_81
老师,您看能否下载
2021-05-04
共3条回复

Vue3 + TS 仿知乎专栏企业级项目

带你完成前后端分离复杂项目,率先掌握 vue3 造轮子技能

3142 学习 · 2313 问题

查看课程