最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

封裝一個(gè)Vue文件上傳組件案例詳情

 更新時(shí)間:2022年08月15日 08:41:09   作者:大龍BBG???????  
這篇文章主要介紹了封裝一個(gè)Vue文件上傳組件案例詳情,文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下

前言

在面向特定用戶的項(xiàng)目中,引 其他ui組件庫(kù)導(dǎo)致打包體積過(guò)大,首屏加載緩慢,還需要根據(jù)UI設(shè)計(jì)師設(shè)計(jì)的樣式,重寫大量的樣式覆蓋引入的組件庫(kù)的樣式。因此嘗試自己封裝一個(gè)自己的組件,代碼參考了好多前輩的文章

1. 子組件

<template>
    <div class="digital_upload">
        <input
            style="display: none"
            @change="addFile"
            :multiple="multiple"
            type="file"
            :name="name"
            :id="id"
            :accept="accept"
        />
        <label :for="id">
            <slot></slot>
        </label>
    </div>
</template>

<script>
export default {
    name: 'my-upload',
    props: {
        name: String,
        action: {
            type: String,
            required: true
        },
        fileList: {
            type: Array,
            default () {
                return []
            }
        },
        accept: {
            type: String,
            require: true
        },
        id: {
            type: String,
            default: 'my-upload'
        },
        data: Object,
        multiple: Boolean,
        limit: Number,
        onChange: Function,
        onBefore: Function,
        onProgress: Function,
        onSuccess: Function,
        onFailed: Function,
        onFinished: Function
    },
    methods: {
        // input的 chang事件處理方法
        addFile ({ target: { files } }) { // input標(biāo)簽觸發(fā)onchange事件時(shí),將文件加入待上傳列表
            for (let i = 0, l = files.length; i < l; i++) {
                files[i].url = URL.createObjectURL(files[i])// 創(chuàng)建blob地址,不然圖片怎么展示?
                files[i].status = 'ready'// 開(kāi)始想給文件一個(gè)字段表示上傳進(jìn)行的步驟的,后面好像也沒(méi)去用......
            }
            let fileList = [...this.fileList]
            if (this.multiple) { // 多選時(shí),文件全部壓如列表末尾
                fileList = [...fileList, ...files]
                const l = fileList.length
                let limit = this.limit
                if (limit && typeof limit === 'number' && Math.ceil(limit) > 0 && l > limit) { // 有數(shù)目限制時(shí),取后面limit個(gè)文件
                    limit = Math.ceil(limit)
                    // limit = limit > 10 ? 10 : limit;
                    fileList = fileList.slice(l - limit)
                }
            } else { // 單選時(shí),只取最后一個(gè)文件。注意這里沒(méi)寫成fileList = files;是因?yàn)閒iles本身就有多個(gè)元素(比如選擇文件時(shí)一下子框了一堆)時(shí),也只要一個(gè)
                fileList = [files[0]]
            }
            this.onChange(fileList)// 調(diào)用父組件方法,將列表緩存到上一級(jí)data中的fileList屬性
        },
        // 移除某一個(gè)文件
        remove (index) {
            const fileList = [...this.fileList]
            if (fileList.length) {
                fileList.splice(index, 1)
                this.onChange(fileList)
            }
        },
        // 檢測(cè)是否可以提交
        checkIfCanUpload () {
            console.log(this.fileList.length)
            return this.fileList.length ? ((this.onBefore && this.onBefore()) || !this.onBefore) : false
        },
        // 根據(jù)情況使用不同的提交的方法
        submit () {
            console.log('開(kāi)始提交')
            if (this.checkIfCanUpload()) {
                // console.log('開(kāi)始提交2')
                if (this.onProgress && typeof XMLHttpRequest !== 'undefined') {
                    this.xhrSubmit()
                } else {
                    this.fetchSubmit()
                }
            }
        },
        // fethc 提交
        fetchSubmit () {
            const keys = Object.keys(this.data); const values = Object.values(this.data); const action = this.action
            const promises = this.fileList.map(each => {
                each.status = 'uploading'
                const 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()是根據(jù)返回值類型使用的,應(yīng)該視情況而定
            })
            Promise.all(promises).then(resArray => { // 多線程同時(shí)開(kāi)始,如果并發(fā)數(shù)有限制,可以使用同步的方式一個(gè)一個(gè)傳,這里不再贅述。
                let success = 0; let failed = 0
                resArray.forEach((res, index) => {
                    if (res.code === 1) {
                        success++ // 統(tǒng)計(jì)上傳成功的個(gè)數(shù),由索引可以知道哪些成功了
                        this.onSuccess(index, res)
                    } else if (res.code === 520) { // 約定失敗的返回值是520
                        failed++ // 統(tǒng)計(jì)上傳失敗的個(gè)數(shù),由索引可以知道哪些失敗了
                        this.onFailed(index, res)
                    }
                })
                return { success, failed } // 上傳結(jié)束,將結(jié)果傳遞到下文
            }).then(this.onFinished) // 把上傳總結(jié)果返回
        },
        // xhr 提交
        // xhrSubmit () {
        //     const _this = this
        //     const options = this.fileList.map((rawFile, index) => ({
        //         file: rawFile,
        //         data: _this.data,
        //         filename: _this.name || 'file',
        //         action: _this.action,
        //         headers: {
        //             Authorization: window.sessionStorage.getItem('token')
        //         },
        //         onProgress (e) {
        //             _this.onProgress(index, e)// 閉包,將index存住
        //         },
        //         onSuccess (res) {
        //             _this.onSuccess(index, res)
        //         },
        //         onError (err) {
        //             _this.onFailed(index, err)
        //         },
        //         onFinished (res) { // ????????這里補(bǔ)充一個(gè)配置
        //             _this.onFinished(res) // ????????
        //         }
        //     }))
        //     const l = this.fileList.length
        //     const send = async options => {
        //         for (let i = 0; i < l; i++) {
        //             await _this.sendRequest(options[i])// 這里用了個(gè)異步方法,按次序執(zhí)行this.sendRequest方法,參數(shù)為文件列表包裝的每個(gè)對(duì)象,this.sendRequest下面緊接著介紹
        //         }
        //     }
        //     send(options)
        // },
        xhrSubmit () {
            const _this = this
            const options = {
                file: this.fileList,
                data: _this.data,
                filename: _this.name || 'file',
                action: _this.action,
                headers: {
                    Authorization: window.sessionStorage.getItem('token')
                },
                onProgress (e) {
                    _this.onProgress(1, e)// 閉包,將index存住
                },
                onSuccess (res) {
                    _this.onSuccess(1, res)
                },
                onError (err) {
                    _this.onFailed(1, err)
                },
                onFinished (res) { // ????????這里補(bǔ)充一個(gè)配置
                    _this.onFinished(res) // ????????
                }
            }
            // this.fileList.map((rawFile, index) => ({
            //     file: rawFile,
            //     data: _this.data,
            //     filename: _this.name || 'file',
            //     action: _this.action,
            //     headers: {
            //         Authorization: window.sessionStorage.getItem('token')
            //     },
            //     onProgress (e) {
            //         _this.onProgress(index, e)// 閉包,將index存住
            //     },
            //     onSuccess (res) {
            //         _this.onSuccess(index, res)
            //     },
            //     onError (err) {
            //         _this.onFailed(index, err)
            //     },
            //     onFinished (res) { // ????????這里補(bǔ)充一個(gè)配置
            //         _this.onFinished(res) // ????????
            //     }
            // }))
            console.log(options)
            _this.sendRequest(options)
            // const l = this.fileList.length
            // const send = async options => {
            //     for (let i = 0; i < l; i++) {
            //         await _this.sendRequest(options[i])// 這里用了個(gè)異步方法,按次序執(zhí)行this.sendRequest方法,參數(shù)為文件列表包裝的每個(gè)對(duì)象,this.sendRequest下面緊接著介紹
            //     }
            // }
            // send(options)
        },
        // 發(fā)起上傳請(qǐng)求這里借鑒了element-ui的上傳源碼
        sendRequest (option) {
            // const _this = this
            upload(option)
            function getError (action, option, xhr) {
                // eslint-disable-next-line no-void
                var msg = void 0
                if (xhr.response) {
                    msg = xhr.status + ' ' + (xhr.response.error || xhr.response)
                } else if (xhr.responseText) {
                    msg = xhr.status + ' ' + xhr.responseText
                } else {
                    msg = 'fail to post ' + action + ' ' + xhr.status
                }
                var err = new Error(msg)
                err.status = xhr.status
                err.method = 'post'
                err.url = action
                return err
            }

            function getBody (xhr) {
                var text = xhr.responseText || xhr.response
                if (!text) {
                    return text
                }

                try {
                    return JSON.parse(text)
                } catch (e) {
                    return text
                }
            }

            function upload (option) {
                if (typeof XMLHttpRequest === 'undefined') {
                    return
                }

                var xhr = new XMLHttpRequest()
                var action = option.action

                if (xhr.upload) {
                    xhr.upload.onprogress = function progress (e) {
                        if (e.total > 0) {
                            e.percent = e.loaded / e.total * 100
                        }
                        option.onProgress(e)
                    }
                }
                var formData = new FormData()

                if (option.data) {
                    Object.keys(option.data).map(function (key) {
                        formData.append(key, option.data[key])
                    })
                }

                option.file.forEach(item => {
                    formData.append(option.filename, item)
                })
                // formData.append(option.filename, option.file)

                xhr.onerror = function error (e) {
                    option.onError(e)
                }

                xhr.onload = function onload () {
                    if (xhr.status < 200 || xhr.status >= 300) {
                        return option.onError(getError(action, option, xhr))
                    }

                    option.onSuccess(getBody(xhr))
                }

                xhr.open('post', action, true)

                if (option.withCredentials && 'withCredentials' in xhr) {
                    xhr.withCredentials = true
                }

                var headers = option.headers || {}

                for (var item in headers) {
                    // eslint-disable-next-line no-prototype-builtins
                    if (headers.hasOwnProperty(item) && headers[item] !== null) {
                        xhr.setRequestHeader(item, headers[item])
                    }
                }
                xhr.send(formData)
                return xhr
            }
        }
    }
}
</script>
<style lang="less" scoped>
</style>

2 父組件使用

<template>
    <div id="upload_works">
        <div class="type_info" >
            <div class="info">支持JPG,PNG,GIF格式,大小不超過(guò)20M</div>
            <!-- 自己封裝的手動(dòng)上傳文件的組件 -->
            <digital-upload
                accept="image/*"
                ref="myUpload"
                action="/api/production/uploadImgList"
                name="files"
                id="my-upload"
                multiple
                :limit="10"
                :file-list="fileList"
                :data="param"
                :on-change="onChange"
                :on-progress="uploadProgress"
                :on-success="uploadSuccess"
                :on-failed="uploadFailed"
                :on-finished="onFinished"
            >
                <div class="normal_button">上傳文件</div>
            </digital-upload>
            <div class="three">或拖放到這里</div>
        </div>
    </div>
</template>

<script>
import digitalUpload from '@/digitalComponents/upload/digitalUpload.vue'
export default {
    data () {
        return {
            fileList: [],
            param: { id: null }
        }
    },
    methods: {
        onChange (fileList) { // 監(jiān)聽(tīng)文件變化,增減文件時(shí)都會(huì)被子組件調(diào)用
            console.log(fileList)
            this.fileList = [...fileList]
        },
        uploadSuccess (index, response) { // 某個(gè)文件上傳成功都會(huì)執(zhí)行該方法,index代表列表中第index個(gè)文件
            console.log('圖片上傳成功')
            console.log(index, response)
            this.submitWorksCover()
        },
        upload () { // 觸發(fā)子組件的上傳方法
            this.$refs.myUpload.submit()
        },
        removeFile (index) { // 移除某文件
            this.$refs.myUpload.remove(index)
        },
        uploadProgress (index, progress) { // 上傳進(jìn)度,上傳時(shí)會(huì)不斷被觸發(fā),需要進(jìn)度指示時(shí)會(huì)很有用
            const { percent } = progress
            console.log(index, percent)
        },
        uploadFailed (index, err) { // 某文件上傳失敗會(huì)執(zhí)行,index代表列表中第index個(gè)文件
            console.log(index, err)
        },
        onFinished (result) { // 所有文件上傳完畢后(無(wú)論成敗)執(zhí)行,result: { success: 成功數(shù)目, failed: 失敗數(shù)目 }
            console.log(result)
        }
    },
    components: {
        digitalUpload
    }
}
</script>
<style lang="less" scoped>
</style>

3.效果

4.總結(jié)

前端項(xiàng)目如果不是中臺(tái)項(xiàng)目,自己封裝組件是非常有比較的,這里比較麻煩的地方是 父組件引用需要些大量的方法,您也可以再封

到此這篇關(guān)于 封裝一個(gè)Vue文件上傳組件案例詳情的文章就介紹到這了,更多相關(guān)Vue 封裝文件上傳組件內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Vue中provide和inject的使用教程詳解

    Vue中provide和inject的使用教程詳解

    在?Vue?中,provide?和?inject?是用于實(shí)現(xiàn)祖先組件向后代組件傳遞數(shù)據(jù)的一種方式,本文主要來(lái)和大家詳細(xì)講講provide和inject的使用方法,希望對(duì)大家有所幫助
    2024-02-02
  • 使用vue/cli出現(xiàn)defineConfig?is?not?function錯(cuò)誤解決辦法

    使用vue/cli出現(xiàn)defineConfig?is?not?function錯(cuò)誤解決辦法

    這篇文章主要給大家介紹了關(guān)于使用vue/cli出現(xiàn)defineConfig?is?not?function錯(cuò)誤的解決辦法,當(dāng)我們?cè)谧龃虬渲玫臅r(shí)候,出現(xiàn)了這個(gè)錯(cuò)誤,需要的朋友可以參考下
    2023-11-11
  • vue在mounted中window.onresize不生效問(wèn)題及解決

    vue在mounted中window.onresize不生效問(wèn)題及解決

    這篇文章主要介紹了vue中在mounted中window.onresize不生效問(wèn)題及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-04-04
  • vue2中vue-router引入使用詳解

    vue2中vue-router引入使用詳解

    Vue?Router?是?Vue?的官方路由,它與?Vue.js?核心深度集成,讓用?Vue.js?構(gòu)建單頁(yè)應(yīng)用變得輕而易舉,下面就跟隨小編一起學(xué)習(xí)一下vue-router的具體用法吧
    2023-12-12
  • 通用vue組件化展示列表數(shù)據(jù)實(shí)例詳解

    通用vue組件化展示列表數(shù)據(jù)實(shí)例詳解

    組件化開(kāi)發(fā)能大幅提高應(yīng)用的開(kāi)發(fā)效率、測(cè)試性、復(fù)用性等,下面這篇文章主要給大家介紹了關(guān)于通用vue組件化展示列表數(shù)據(jù)的相關(guān)資料,文中通過(guò)圖文介紹的非常詳細(xì),需要的朋友可以參考下
    2023-06-06
  • 前端vue3中的ref與reactive用法及區(qū)別總結(jié)

    前端vue3中的ref與reactive用法及區(qū)別總結(jié)

    這篇文章主要給大家介紹了關(guān)于前端vue3中的ref與reactive用法及區(qū)別的相關(guān)資料,關(guān)于ref及reactive的用法,還是要在開(kāi)發(fā)中多多使用,遇到響應(yīng)式失效問(wèn)題,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-08-08
  • vue.js內(nèi)部自定義指令與全局自定義指令的實(shí)現(xiàn)詳解(利用directive)

    vue.js內(nèi)部自定義指令與全局自定義指令的實(shí)現(xiàn)詳解(利用directive)

    這篇文章主要給大家介紹了關(guān)于vue.js內(nèi)部自定義指令與全局自定義指令的實(shí)現(xiàn)方法,vue.js中實(shí)現(xiàn)自定義指令的主要是利用directive,directive這個(gè)單詞是我們寫自定義指令的關(guān)鍵字,需要的朋友們下面跟著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-07-07
  • vue中el-form-item展開(kāi)項(xiàng)居中的實(shí)現(xiàn)方式

    vue中el-form-item展開(kāi)項(xiàng)居中的實(shí)現(xiàn)方式

    這篇文章主要介紹了vue中el-form-item展開(kāi)項(xiàng)居中的實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-10-10
  • Element樹(shù)形控件整合帶圖標(biāo)的下拉菜單(tree+dropdown+input)

    Element樹(shù)形控件整合帶圖標(biāo)的下拉菜單(tree+dropdown+input)

    Element UI 官網(wǎng)提供的樹(shù)形控件包含基礎(chǔ)的、可選擇的、自定義節(jié)點(diǎn)內(nèi)容的、帶節(jié)點(diǎn)過(guò)濾的以及可拖拽節(jié)點(diǎn)的樹(shù)形結(jié)構(gòu),本文實(shí)現(xiàn)了樹(shù)形控件整合帶圖標(biāo)的下拉菜單,感興趣的可以了解一下
    2021-07-07
  • 詳解vue-cli3多頁(yè)應(yīng)用改造

    詳解vue-cli3多頁(yè)應(yīng)用改造

    這篇文章主要介紹了詳解vue-cli3多頁(yè)應(yīng)用改造,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2019-06-06

最新評(píng)論

巴楚县| 栾城县| 龙南县| 乌审旗| 和平县| 永年县| 凌源市| 卢氏县| 大名县| 深州市| 广河县| 茌平县| 大姚县| 隆回县| 加查县| 洛南县| 淮滨县| 聊城市| 罗源县| 凤山市| 萨嘎县| 旺苍县| 赣榆县| 崇州市| 陈巴尔虎旗| 明水县| 曲松县| 项城市| 望城县| 海淀区| 罗平县| 交口县| 余姚市| 本溪市| 屏边| 博客| 普洱| 尉氏县| 平南县| 冕宁县| 台东市|