欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

vue 實現(xiàn)上傳組件

 更新時間:2021年05月31日 16:19:09   作者:小蟬兒  
雖然前端UI框架大都提供文件上傳的組件,以及很多插件可供選擇,工作中可能不需要我們手寫一個上傳組件,但是從零封裝組件對學習是很有助益的。下文為大家介紹使用Vue3+TypeScript實現(xiàn)的一個文件上傳的功能,目前只實現(xiàn)上傳等基本功能,后續(xù)會逐漸對功能進行擴展

1.介紹

效果如下圖

 

2.思路

文件上傳的兩種實現(xiàn)方式

1.From形式

<form 
  method="post" 
  enctype="multipart/from-data"
  action="api/upload"
>
  <input type="file name="file">
  <button type="submit">Submit</button>
</form>

form的method屬性指定為 "post" 請求,通過HTML表單發(fā)送數(shù)據(jù)給服務器,并返回服務器的修改結果,在這種情況下Content-Type是通過在<form>元素中設置正確的enctype屬性。

form的enctype屬性規(guī)定在發(fā)送到服務器之前應該如何對表單數(shù)據(jù)進行編碼。

  • application/x-www-form-urlencoded(默認值):表示在發(fā)送前編碼所有字符,數(shù)據(jù)被編碼成以"&"分隔的鍵值對,同時以"="分隔鍵和值,("name=seven&age=19")。不支持二進制數(shù)據(jù)。
  • multipart/form-data:支持二進制數(shù)據(jù)(上傳文件時必須指定)

2.JavaScript異步請求形式

我們知道 FormData 接口提供了一種表示表單數(shù)據(jù)的鍵值對 key/value 的構造方式,并且可以輕松的將數(shù)據(jù)通過XMLHttpRequest.send()方法發(fā)送出去,本接口和此方法都相當簡單直接。如果送出時的編碼類型被設為 "multipart/form-data",它會使用和表單一樣的格式。

var formdata = new FormData(); // 創(chuàng)建FormData對象
formdata.append("name","laotie"); // 通過append()方法添加新的屬性值
... // 更多方法請點下面鏈接

FormData接口

3.生命周期

上傳組件也有它的生命周期

beforeUpload --> uploading --> fileUploaded 或者 uploadedError

4.代碼草稿

本例中采用js異步請求的方式開發(fā)上傳組件

<input type="file" name="file" @change.prevent="handleFileChange">
// 創(chuàng)建一個file類型的input,用于觸發(fā)文件上傳,后面可以把input隱藏掉,自定義好看的樣式
// 自定義樣式的時候可以用slot區(qū)分不同上傳狀態(tài)的樣式(loading,success,defult)
const handleFileChange = (e:Event)=>{
  const target = e.target as HTMLInputElement
  const files = Array.from(target.files)// 注意這里取得的是一個類數(shù)組
  if(files){
    // 取得文件
    const uploadedFile = files[0]
    
    if(!validateFormat) return
    // ...這里只是提供一種思路,具體校驗不再講述
    // 在這里做一些上傳文件前的校驗,比如文件格式,大小等,
    // 不符合要求的話就不在繼續(xù)發(fā)送請求
    
    const formData = new FormData()
    formData.append(uploadedFile.name,uploadedFile)
    
    axios.post('/upload',formData,{
      headers:{
         // 注意設置編碼類型
        'Content-Type': 'multipart/form-data'
      }
    }).then(res=>{
      console.log('上傳成功')
    }).catch(error =>{
      // 文件上傳失敗
    }).finally(()=>{
      // 文件上傳完成,無論成功還是失敗
      // 這里可以清除一下input.value
    })
  }
}

5.具體實現(xiàn)

// Upload.vue
<template>
  <div class="upload-container">
    <div class="upload-box" @click.prevent="triggerUpload" v-bind="$attrs">
      <slot name="loading" v-if="fileStatus==='loading'">
        <button class="btn btn-primary">上傳中</button>
      </slot>
      <slot name="uploaded" v-else-if="fileStatus==='success'" :uploadedData="fileData">
        <button class="btn btn-primary">上傳成功</button>
      </slot>
      <slot v-else name="default">
        <button class="btn btn-primary">點擊上傳</button>
      </slot>
    </div>
    <input type="file" class="file-input d-none" name="file" ref="uploadInput" @change="hanldeInput"/>
  </div>
</template>
<script lang="ts">
import { defineComponent, ref, PropType, watch } from 'vue'
import axios from 'axios'
type UploadStatus = 'ready' | 'loading' | 'success' | 'error'
type FunctionProps = (file:File) => boolean
export default defineComponent({
  name: 'Upload',
  inheritAttrs: false,
  props: {
    // 上傳的url
    action: {
      type: String,
      required: true
    },
    // 上傳之前的校驗,是一個返回布爾值的函數(shù)
    beforeUpload: {
      type: Function as PropType<FunctionProps>
    },
    // 上傳好的數(shù)據(jù),用來判斷狀態(tài)或做初始化展示
    uploadedData: {
      type: Object
    }
  },
  emits: ['file-uploaded-success', 'file-uploaded-error'],
  setup(props, ctx) {
    const uploadInput = ref<null | HTMLInputElement>(null)
    const fileStatus = ref<UploadStatus>(props.uploadedData ? 'success' : 'ready')
    const fileData = ref(props.uploadedData)
    watch(() => props.uploadedData, (val) => {
      if (val) {
        fileStatus.value = 'success'
        fileData.value = val
      }
    })
    const triggerUpload = () => {
      if (uploadInput.value) {
        uploadInput.value.click()
      }
    }
    const hanldeInput = (e:Event) => {
      const target = e.target as HTMLInputElement
      const files = target.files
      console.log(target)
      if (files) {
        const uploadFile = Array.from(files)
        const validateFormat = props.beforeUpload ? props.beforeUpload(uploadFile[0]) : true
        if (!validateFormat) return
        fileStatus.value = 'loading'
        const formData = new FormData()
        formData.append('file', uploadFile[0])
        axios.post(props.action, formData, {
          headers: {
            'Content-Type': 'multipart/form-data'
          }
        }).then(res => {
          console.log('文件上傳成功', res)
          fileStatus.value = 'success'
          fileData.value = res.data
          ctx.emit('file-uploaded-success', res.data)
        }).catch(error => {
          console.log('文件上傳失敗', error)
          fileStatus.value = 'error'
          ctx.emit('file-uploaded-error', error)
        }).finally(() => {
          console.log('文件上傳完成')
          if (uploadInput.value) {
            uploadInput.value.value = ''
          }
        })
      }
    }

    return {
      uploadInput,
      triggerUpload,
      hanldeInput,
      fileStatus,
      fileData
    }
  }
})
</script>

使用示例:

<template>
  <div class="create-post-page">
    <upload
      action="/upload"
      :beforeUpload="beforeUpload"
      :uploadedData="uploadedData"
      @file-uploaded-success="hanldeUploadSuccess"
      class="d-flex align-items-center justify-content-center bg-light text-secondary w-100 my-4"
      >
      <template #uploaded="slotProps">
        <div class="uploaded-area">
          <img :src="slotProps.uploadedData.data.url"/>
          <h3>點擊重新上傳</h3>
        </div>
       </template>
       <template #default>
         <h2>點擊上傳頭圖</h2>
       </template>
       <template #loading>
         <div class="d-flex">
          <div class="spinner-border text-secondary" role="status">
            <span class="sr-only"></span>
          </div>
         </div>
       </template>
    </upload>
  </div>
</template>
<script lang="ts">
import { defineComponent, ref, onMounted } from 'vue'
import Upload from '../components/Upload.vue'
import createMessage from '../components/createMessage'

export default defineComponent({
  name: 'CreatePost',
  components: { Upload },
  setup() {
    const uploadedData = ref() //創(chuàng)建一個響應式數(shù)據(jù)
    let imageId = ''
    onMounted(() => {
      ....
      // 這里有邏輯省略了,取到初始化數(shù)據(jù)image
      if (image) {
        uploadedData.value = { data: image }
      }
    })
    // 上傳前校驗,返回布爾值
    const beforeUpload = (file:File) => {
      const res = beforeUploadCheck(file, {
        format: ['image/jpeg', 'image/png'],
        size: 1
      })
      const { error, passed } = res
      if (error === 'format') {
        createMessage('上傳圖片只能是JPG/PNG格式!', 'error')
      }
      if (error === 'size') {
        createMessage('上傳圖片大小不能超過1MB', 'error')
      }
      return passed
    }
    // 上傳成功后拿到imageId就可以進行后續(xù)處理,創(chuàng)建表單啥的
    const hanldeUploadSuccess = (res:ResponeseProps<ImageProps>) => {
      createMessage(`上傳圖片ID ${res.data._id}`, 'success')
      if (res.data._id) {
        imageId = res.data._id
      }
    }
    return {
      beforeUpload,
      hanldeUploadSuccess,
      uploadedData
    }
  }
})
</script>
<style>
.create-post-page{
  padding:0 20px 20px;
}
.create-post-page .upload-box{
  height:200px;
  cursor: pointer;
  overflow: hidden;
}
.create-post-page .upload-box img{
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.uploaded-area{
  position: relative;
}
.uploaded-area:hover h3{
  display: block;
}
.uploaded-area h3{
  display: none;
  position: absolute;
  color: #999;
  text-align: center;
  width: 100%;
  top:50%
}
</style>

以上就是vue 實現(xiàn)上傳組件的詳細內(nèi)容,更多關于vue 上傳組件的資料請關注腳本之家其它相關文章!

相關文章

  • Vue如何在CSS中使用data定義的數(shù)據(jù)淺析

    Vue如何在CSS中使用data定義的數(shù)據(jù)淺析

    這篇文章主要給大家介紹了關于Vue如何在CSS中使用data定義的數(shù)據(jù)的相關資料,文中通過實例代碼介紹的非常詳細,對大家學習或者使用vue具有一定的參考學習價值,需要的朋友可以參考下
    2022-05-05
  • 在Vue中獲取組件聲明時的name屬性方法

    在Vue中獲取組件聲明時的name屬性方法

    今天小編就為大家分享一篇在Vue中獲取組件聲明時的name屬性方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-09-09
  • VueJS 取得 URL 參數(shù)值的方法

    VueJS 取得 URL 參數(shù)值的方法

    form-create 是一個可以通過 JSON 生成具有動態(tài)渲染、數(shù)據(jù)收集、驗證和提交功能的表單生成器。本文給大家簡單介紹了VueJS U取得RL 參數(shù)值的方法,詳細給大家介紹了vue自定義表單生成器可根據(jù)json參數(shù)動態(tài)生成表單效果,感興趣的朋友一起看看吧
    2019-07-07
  • Django與Vue語法的沖突問題完美解決方法

    Django與Vue語法的沖突問題完美解決方法

    這篇文章主要介紹了Django與Vue語法的沖突問題完美解決方法,本文給大家分享了兩種解決方法,需要的朋友參考下吧
    2017-12-12
  • vue實現(xiàn)消息的無縫滾動效果的示例代碼

    vue實現(xiàn)消息的無縫滾動效果的示例代碼

    本篇文章主要介紹了vue實現(xiàn)消息的無縫滾動效果的示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-12-12
  • Vue3實現(xiàn)動態(tài)導入Excel表格數(shù)據(jù)的方法詳解

    Vue3實現(xiàn)動態(tài)導入Excel表格數(shù)據(jù)的方法詳解

    在開發(fā)工作過程中,我們會遇到各種各樣的表格數(shù)據(jù)導入,動態(tài)數(shù)據(jù)導入可以減少人為操作,減少出錯。本文為大家介紹了Vue3實現(xiàn)動態(tài)導入Excel表格數(shù)據(jù)的方法,需要的可以參考一下
    2022-11-11
  • Vue.js實現(xiàn)文章評論和回復評論功能

    Vue.js實現(xiàn)文章評論和回復評論功能

    這篇文章主要為大家詳細介紹了Vue.js實現(xiàn)文章評論和回復評論功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-04-04
  • 在antd Table中插入可編輯的單元格實例

    在antd Table中插入可編輯的單元格實例

    這篇文章主要介紹了在antd Table中插入可編輯的單元格實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-10-10
  • vite+vue3+tsx項目打包后動態(tài)路由無法加載頁面的問題及解決

    vite+vue3+tsx項目打包后動態(tài)路由無法加載頁面的問題及解決

    這篇文章主要介紹了vite+vue3+tsx項目打包后動態(tài)路由無法加載頁面的問題及解決,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-03-03
  • vue axios數(shù)據(jù)請求get、post方法及實例詳解

    vue axios數(shù)據(jù)請求get、post方法及實例詳解

    axios是一個基于Promise,同時支持瀏覽器端和Node.js的HTTP庫,常用于Ajax請求。這篇文章主要介紹了vue axios數(shù)據(jù)請求get、post方法的使用 ,需要的朋友可以參考下
    2018-09-09

最新評論