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

利用Vue3和element-plus實(shí)現(xiàn)圖片上傳組件

 更新時(shí)間:2022年03月15日 10:27:59   作者:之一Yo  
element-plus提供了uploader組件,但是不好定制化。所以本文將利用Vue3和element-plus實(shí)現(xiàn)一個(gè)圖片上傳的組件,感興趣的可以了解一下

前言

element-plus 提供了 uploader 組件,但是不好定制化,所以自己又造了個(gè)輪子,實(shí)現(xiàn)了一個(gè)圖片上傳的組件,它的預(yù)期行為是:

1.還沒(méi)上傳圖片時(shí),顯示上傳卡片

2.上傳圖片時(shí)顯示進(jìn)度條,隱藏上傳卡片

3.上傳成功時(shí)顯示圖片縮略圖,上傳失敗則顯示失敗提示

4.支持上傳圖片的預(yù)覽和刪除

具體如下圖所示:

具體代碼

圖片上傳

這里使用的圖床是牛圖網(wǎng),無(wú)需注冊(cè),貌似也沒(méi)有圖片大小的限制,但是請(qǐng)不要上傳違規(guī)圖像。

<code>import axios from "axios"
import { ElMessage } from 'element-plus'


const service = axios.create({
    baseURL: "/image"
})

service.interceptors.response.use(response => {
    const code = response.data.code || 200
    if (code === 200) {
        return response.data.data
    }

    let msg = response.data.code + " " + response.data.msg
    ElMessage.error(msg)

    return Promise.reject('上傳圖片失?。? + msg)
})

/**
 * 上傳圖片
 * @param {File} file 圖片文件
 * @param {RefImpl} progress 上傳進(jìn)度
 * @returns promise
 */
function uploadImage(file, progress) {
    let formData = new FormData();
    formData.append("file", file)
    return service({
        url: "/upload",
        method: "post",
        data: formData,
        onUploadProgress(event) {
            let v = Math.round(event.loaded / event.total * 100)
            progress.value = v == 100 ? 80 : v
        },

    })
}

export { uploadImage }

這里使用 onUploadProgress 來(lái)監(jiān)視上傳進(jìn)度,但是實(shí)際上直接使用計(jì)算出來(lái)的進(jìn)度往往會(huì)和實(shí)際的存在很大的偏差,也就是說(shuō):即使你還在上傳,axios 也會(huì)告訴你已經(jīng)上傳完了,所以這里把 100 的進(jìn)度換成了 80,真正的 100 進(jìn)度應(yīng)該在服務(wù)器返回 url 時(shí)設(shè)置。

受到同源策略的限制,我們需要在 vue.config.js 中配置一下代理服務(wù)器:

<code>module.exports = {
    devServer: {
        proxy: {
            "/image": {
                target: "https://niupic.com/api",
                pathRewrite: { "^/image": "" },
            },
        }
    }
}

上傳組件

圖片預(yù)覽功能用的是 vue-easy-light-box,如果沒(méi)有安裝的話(huà)可以 npm install --save vue-easy-lightbox@next 安裝一下。下面是具體代碼:

<code><template>
    <div class="uploader">
        <input
            type="file"
            id="file-input"
            style="display: none"
            accept="image/*"
            @change="onImageAdded"
        />

        <div
            class="card upload-card"
            @click="openFileDialog"
            v-if="!isThumbnailVisible"
        >
            <svg
                class="icon"
                width="28"
                height="28"
                viewBox="0 0 1024 1024"
                xmlns="http://www.w3.org/2000/svg"
            >
                <path
                    fill="#8c939d"
                    d="M480 480V128a32 32 0 0164 0v352h352a32 32 0 110 64H544v352a32 32 0 11-64 0V544H128a32 32 0 010-64h352z"
                ></path>
            </svg>
        </div>

        <div class="card thumbnail-card" v-show="isThumbnailVisible">
            <img src="" alt="縮略圖" id="thumbnail" />

            <label class="success-label" v-show="isSuccessLabelVisible"
                ><i class="success-icon"
                    ><svg
                        class="icon"
                        width="12"
                        height="12"
                        viewBox="0 0 1024 1024"
                        xmlns="http://www.w3.org/2000/svg"
                    >
                        <path
                            fill="white"
                            d="M406.656 706.944L195.84 496.256a32 32 0 10-45.248 45.248l256 256 512-512a32 32 0 00-45.248-45.248L406.592 706.944z"
                        ></path></svg
                ></i>
            </label>

            <!-- 圖標(biāo) -->
            <div class="thumbnail-actions">
                <span class="thumbnail-preview" @click="handleThumbnailPreview">
                    <svg
                        class="icon"
                        width="20"
                        height="20"
                        viewBox="0 0 1024 1024"
                        xmlns="http://www.w3.org/2000/svg"
                    >
                        <path
                            fill="white"
                            d="M795.904 750.72l124.992 124.928a32 32 0 01-45.248 45.248L750.656 795.904a416 416 0 1145.248-45.248zM480 832a352 352 0 100-704 352 352 0 000 704zm-32-384v-96a32 32 0 0164 0v96h96a32 32 0 010 64h-96v96a32 32 0 01-64 0v-96h-96a32 32 0 010-64h96z"
                        ></path>
                    </svg>
                </span>

                <span class="thumbnail-delete" @click="handleThumbnailRemove">
                    <svg
                        class="icon"
                        width="20"
                        height="20"
                        viewBox="0 0 1024 1024"
                        xmlns="http://www.w3.org/2000/svg"
                    >
                        <path
                            fill="white"
                            d="M160 256H96a32 32 0 010-64h256V95.936a32 32 0 0132-32h256a32 32 0 0132 32V192h256a32 32 0 110 64h-64v672a32 32 0 01-32 32H192a32 32 0 01-32-32V256zm448-64v-64H416v64h192zM224 896h576V256H224v640zm192-128a32 32 0 01-32-32V416a32 32 0 0164 0v320a32 32 0 01-32 32zm192 0a32 32 0 01-32-32V416a32 32 0 0164 0v320a32 32 0 01-32 32z"
                        ></path>
                    </svg>
                </span>
            </div>

            <!-- 進(jìn)度條 -->
            <el-progress
                type="circle"
                :percentage="progress"
                v-show="isProgressVisible"
                :width="110"
                id="progress"
            />
        </div>

        <vue-easy-lightbox
            moveDisabled
            :visible="isLightBoxVisible"
            :imgs="localImageUrl"
            :index="index"
            @hide="handleLightboxHide"
        />
    </div>
</template>

<script>
import { ref, computed } from "vue";
import { uploadImage } from "../api/image";
import { Plus } from "@element-plus/icons-vue";
import VueEasyLightbox from "vue-easy-lightbox";
import { ElMessage } from 'element-plus/lib/components';

export default {
    name: "KilaKilaUploader",
    emits: ["uploaded", "aboutToUpload", "removed"],
    components: { Plus, VueEasyLightbox },
    setup(props, context) {
        let progress = ref(0);
        let isLightBoxVisible = ref(false);
        let isProgressVisible = ref(false);
        let isSuccessLabelVisible = ref(false);
        let imageUrl = ref("");
        let localImageUrl = ref("");
        let index = ref(0);

        let isThumbnailVisible = computed(() => localImageUrl.value.length > 0);

        function openFileDialog() {
            document.getElementById("file-input").click();
        }

        function onImageAdded() {
            let fileInput = document.getElementById("file-input");
            if (fileInput.files.length == 0) {
                return;
            }

            context.emit("aboutToUpload");
            let file = fileInput.files[0];
            setImageUrl(URL.createObjectURL(file));
            upload(file);
        }

        function setImageUrl(url) {
            let thumbnailEl = document.getElementById("thumbnail");
            thumbnailEl.src = localImageUrl.value = url;
        }

        function handleThumbnailRemove(file) {
            imageUrl.value = "";
            localImageUrl.value = "";
            context.emit("removed", file);
        }

        function handleThumbnailPreview() {
            isLightBoxVisible.value = true;
        }

        function handleLightboxHide() {
            isLightBoxVisible.value = false;
        }

        function upload(file) {
            progress.value = 0;
            isProgressVisible.value = true;
            isSuccessLabelVisible.value = false;

            uploadImage(file, progress).then(
                (url) => {
                    progress.value = 100;
                    imageUrl.value = url;
                    document.getElementById("thumbnail").src = url;
                    context.emit("uploaded", url);

                    setTimeout(() => {
                        isProgressVisible.value = false;
                        isSuccessLabelVisible.value = true;
                    }, 200);
                },
                () => {
                    isProgressVisible.value = false;
                    localImageUrl.value = "";
                    context.emit("uploaded", "");
                    ElMessage.error("哎呀,圖片上傳出錯(cuò)啦~")
                }
            );
        }

        return {
            progress,
            imageUrl,
            localImageUrl,
            index,
            isLightBoxVisible,
            isThumbnailVisible,
            isProgressVisible,
            isSuccessLabelVisible,
            handleThumbnailRemove,
            handleThumbnailPreview,
            handleLightboxHide,
            openFileDialog,
            onImageAdded,
            setImageUrl,
        };
    },
};
</script>

<style lang="less" scoped>
.uploader {
    display: flex;
}

.card {
    background-color: #fbfdff;
    border: 1px dashed #c0ccda;
    border-radius: 6px;
    width: 148px;
    height: 148px;
    overflow: hidden;
}

.upload-card {
    display: flex;
    justify-content: center;
    align-items: center;
    transition: all 0.3s;
    cursor: pointer;

    &:hover {
        border-color: #409eff;
        color: #409eff;
    }
}

.thumbnail-card {
    border: 1px solid #c0ccda;
    position: relative;

    #thumbnail {
        width: 100%;
        height: 100%;
        object-fit: contain;
        display: inline;
    }

    .success-label {
        position: absolute;
        right: -15px;
        top: -6px;
        width: 40px;
        height: 24px;
        background: #67c23a;
        text-align: center;
        transform: rotate(45deg);
        box-shadow: 0 0 1pc 1px #0003;

        .success-icon {
            position: absolute;
            left: 13px;
            top: 1px;
            transform: rotate(-45deg);
        }
    }

    #progress {
        width: 100%;
        height: 100%;
        position: absolute;
        top: 0;
        left: 0;
        background: rgba(255, 255, 255, 0.7);

        :deep(.el-progress-circle) {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
        }
    }

    .thumbnail-actions {
        width: 100%;
        height: 100%;
        background: rgba(0, 0, 0, 0.5);
        opacity: 0;
        transition: all 0.4s ease;
        display: flex;
        justify-content: center;
        align-items: center;
        position: absolute;
        top: 0;
        left: 0;
        border-radius: 6px;

        .thumbnail-preview,
        .thumbnail-delete {
            cursor: pointer;
            margin: 0 8px;
            display: inline-block;
        }

        &:hover {
            opacity: 1;
        }
    }
}

:deep(.vel-img) {
    box-shadow: 0 5px 20px 2px rgba(0, 0, 0, 0.35);
}
</style>

在圖片上傳之前、上傳完成和移除圖片的時(shí)候都會(huì)觸發(fā)相應(yīng)的自定義事件,父級(jí)組件可以處理這些事件來(lái)設(shè)置圖片 url。

以上就是利用Vue3和element-plus實(shí)現(xiàn)圖片上傳組件的詳細(xì)內(nèi)容,更多關(guān)于Vue3 element-plus圖片上傳的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Vant 中的Toast設(shè)置全局的延遲時(shí)間操作

    Vant 中的Toast設(shè)置全局的延遲時(shí)間操作

    這篇文章主要介紹了Vant 中的Toast設(shè)置全局的延遲時(shí)間操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-11-11
  • vuex與組件聯(lián)合使用的方法

    vuex與組件聯(lián)合使用的方法

    Vuex 是一個(gè)專(zhuān)為 Vue.js 應(yīng)用程序開(kāi)發(fā)的狀態(tài)管理模式。這篇文章主要介紹了vuex與組件聯(lián)合使用的方法,需要的朋友可以參考下
    2018-05-05
  • 淺析vue-router實(shí)現(xiàn)原理及兩種模式

    淺析vue-router實(shí)現(xiàn)原理及兩種模式

    這篇文章主要介紹了vue-router實(shí)現(xiàn)原理及兩種模式分析,給大家介紹了vue-router hash模式與history模式不同模式下處理邏輯,需要的朋友可以參考下
    2020-02-02
  • 最簡(jiǎn)單的vue消息提示全局組件的方法

    最簡(jiǎn)單的vue消息提示全局組件的方法

    這篇文章主要介紹了最簡(jiǎn)單的vue消息提示全局組件的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2019-06-06
  • 保姆級(jí)Vue3開(kāi)發(fā)教程分享

    保姆級(jí)Vue3開(kāi)發(fā)教程分享

    這篇Vue3開(kāi)發(fā)文檔,包含了 Vue3 開(kāi)發(fā)中使用的所有語(yǔ)法,文中的示例代碼講解詳細(xì),希望所有像他一樣還不熟的伙伴快速上手 Vue3,不會(huì)的再不看要遭老罪咯
    2023-04-04
  • vue預(yù)覽 pdf、word、xls、ppt、txt文件的實(shí)現(xiàn)方法

    vue預(yù)覽 pdf、word、xls、ppt、txt文件的實(shí)現(xiàn)方法

    這篇文章主要介紹了vue預(yù)覽 pdf、word、xls、ppt、txt文件的實(shí)現(xiàn)方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-04-04
  • 關(guān)于Vue中this.$set的正確使用

    關(guān)于Vue中this.$set的正確使用

    我們?cè)陧?xiàng)目開(kāi)發(fā)的過(guò)程中,經(jīng)常會(huì)遇到這種情況:為data中的某一個(gè)對(duì)象添加一個(gè)屬性,我們?cè)撊绾谓鉀Q這個(gè)問(wèn)題呢,下面小編給大家?guī)?lái)了Vue中this.$set的正確使用,感興趣的朋友跟隨小編一起看看吧
    2022-12-12
  • Vue實(shí)現(xiàn)手機(jī)橫屏效果的代碼示例

    Vue實(shí)現(xiàn)手機(jī)橫屏效果的代碼示例

    有時(shí)候一些頁(yè)面希望在手機(jī)上可以實(shí)現(xiàn)橫屏的效果,比如播放頁(yè)面,所以本文我們講給大家介紹Vue如何實(shí)現(xiàn)手機(jī)橫屏效果,文章通過(guò)代碼示例介紹的非常詳細(xì),感興趣的同學(xué)跟著小編一起來(lái)看看吧
    2023-08-08
  • Vue3中使用qrcode庫(kù)實(shí)現(xiàn)二維碼生成

    Vue3中使用qrcode庫(kù)實(shí)現(xiàn)二維碼生成

    Vue3中實(shí)現(xiàn)二維碼生成需要使用第三方庫(kù)來(lái)處理生成二維碼的邏輯,常用的庫(kù)有?qrcode和?vue-qrcode,本文主要介紹了Vue3中使用qrcode庫(kù)實(shí)現(xiàn)二維碼生成,感興趣的可以了解一下
    2023-12-12
  • 解決Vue中mounted鉤子函數(shù)獲取節(jié)點(diǎn)高度出錯(cuò)問(wèn)題

    解決Vue中mounted鉤子函數(shù)獲取節(jié)點(diǎn)高度出錯(cuò)問(wèn)題

    本篇文章給大家分享了如何解決Vue中mounted鉤子函數(shù)獲取節(jié)點(diǎn)高度出錯(cuò)問(wèn)題,對(duì)此有興趣的朋友可以參考學(xué)習(xí)下。
    2018-05-05

最新評(píng)論