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

ElementUI修改實(shí)現(xiàn)更好用圖片上傳預(yù)覽組件

 更新時(shí)間:2022年09月30日 09:02:44   作者:MiyueFE  
這篇文章主要為大家介紹了ElementUI修改實(shí)現(xiàn)更好用圖片上傳預(yù)覽組件示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

前言

嗯,,,跟之前封裝“全局 Loading”的出發(fā)點(diǎn)基本一樣,因?yàn)楫a(chǎn)品覺得 ElementUI 提供的默認(rèn)上傳組件,使用“照片墻”或者“縮略圖”模式都需要去改動原本的組件樣式,并且縮略圖尺寸也不能調(diào)整,預(yù)覽模式也會對原始圖片進(jìn)行縮放和處理,不符合系統(tǒng)本身的樣式規(guī)范。

最離譜的是,預(yù)覽模式居然有背景色,但是背景色又沒有填滿整個(gè) model 的背景區(qū)域,,,甚至還出現(xiàn)了滾動條!??!

所以,為了更好的配合產(chǎn)品和UI,特地重新編寫了一個(gè)圖片上傳組件。

1. 功能設(shè)計(jì)

嗯,既然是圖片上傳,那么肯定只支持圖片文件了。因?yàn)槭莾?nèi)部項(xiàng)目,所以也保留了 http 上傳部分,大家可以參照 ElementUI 適當(dāng)修改。

修改后的上傳組件支持以下功能:

  • 上傳(基礎(chǔ)中的基礎(chǔ))
  • 實(shí)現(xiàn) v-model 語法糖綁定上傳數(shù)據(jù)列表(嗯,,,也很基礎(chǔ))
  • 需要支持大圖預(yù)覽
  • 不能換行,超出寬度顯示滾動條且支持鼠標(biāo)控制(不用 shift 的那種)

功能設(shè)計(jì)完成之后,大致的頁面樣式就是這樣的:

2. 實(shí)現(xiàn)

為了能夠適應(yīng)更多的場景,我決定把預(yù)覽部分也直接提取出來。

2.1 圖片預(yù)覽 PicturePreviewer

這里的圖片預(yù)覽是基于 ElDialog 開發(fā)的,支持翻頁、循環(huán)等。

本身不依賴外部的圖片元素,可以和 ElDialog 一樣直接使用 visible 屬性來控制顯示和隱藏。

 <template>
   <el-dialog
     :title="title"
     :visible="visible"
     :close-on-click-modal="false"
     width="1000px"
     destroy-on-close
     append-to-body
     @close="closeDialog"
   >
     <div class="q-picture__img-box">
       <div
         class="q-picture__prev-btn"
         @mouseover="leftBtnStatus = true"
         @mouseleave="leftBtnStatus = false"
       >
         <transition name="btn-fade">
           <el-button
             v-show="leftBtnStatus && isNeeding"
             circle
             icon="el-icon-arrow-left"
             @click="lastImage()"
           />
         </transition>
       </div>
       <img v-show="visible" :src="currentSrc" alt="" v-loading="loading" @load="loading = false" />
       <div
         class="q-picture__next-btn"
         @mouseover="rightBtnStatus = true"
         @mouseleave="rightBtnStatus = false"
       >
         <transition name="btn-fade">
           <el-button
             v-show="rightBtnStatus && isNeeding"
             circle
             icon="el-icon-arrow-right"
             @click="nextImage()"
           />
         </transition>
       </div>
     </div>
   </el-dialog>
 </template>
 <script>
 export default {
   name: "PicturePreviewer",
   props: {
     visible: { type: Boolean, default: false },
     pageable: { type: Boolean, default: true },
     recyclable: { type: Boolean, default: true },
     src: { type: [String, Array], required: true },
     title: { type: String, default: "圖片預(yù)覽" },
     current: { type: Number, default: 0 }
   },
   data() {
     return {
       currentKey: -1,
       leftBtnStatus: false,
       rightBtnStatus: false,
       loading: false
     };
   },
   computed: {
     isNeeding: function () {
       return typeof this.src === "object" && this.pageable && this.src && this.src.length > 1;
     },
     currentSrc: function () {
       if (typeof this.src === "string") return this.src;
       if (this.src && this.src.length) {
         return this.src[this.currentKey] || "";
       }
       return "";
     }
   },
   methods: {
     closeDialog() {
       this.$emit("update:visible", false);
     },
     lastImage() {
       if (this.currentKey - 1 === -1) {
         if (this.recyclable) this.currentKey = this.src.length - 1;
         else this.$message.info("當(dāng)前已經(jīng)是第一張圖片");
       } else {
         this.currentKey = this.currentKey - 1;
       }
     },
     nextImage() {
       if (this.currentKey + 1 === this.src.length) {
         if (this.recyclable) this.currentKey = 0;
         else this.$message.info("當(dāng)前已經(jīng)是最后一張圖片");
       } else {
         this.currentKey = this.currentKey + 1;
       }
     }
   },
   watch: {
     current: {
       handler: function (val) {
         if (val) this.currentKey = val;
         else this.currentKey = 0;
       },
       immediate: true
     }
   }
 };
 </script>

2.2 圖片上傳 ImageUpload

圖片預(yù)覽處理完成夠,就可以處理圖片上傳了。

 <template>
   <div
     class="q-upload__preview"
     ref="pictures"
     :title="messageInfo"
     @mouseenter="horizontalRolling"
   >
     <slot name="preSlot"></slot>
     <input
       class="q-upload__file-input"
       type="file"
       ref="fileInput"
       name="fileInput"
       @change="fileChange"
       :accept="accept"
     />
     <div
       class="q-upload__file-label"
       v-loading="fileLoading"
       @click="selectFile"
       v-show="fileLists.length < limitNum && !disabled"
     >
       <i class="el-icon-plus"></i>
     </div>
     <slot name="middle"></slot>
     <div class="q-upload__pre-img" v-for="(i, k) in fileLists" :key="i.smallUrl">
       <img class="q-upload__img" :src="i.smallUrl ? i.smallUrl : i.url" />
       <div class="q-upload__mask">
         <i v-if="prev" class="el-icon-zoom-in" @click="imgPreview(i, k)"></i>
         <i class="el-icon-delete" v-if="!disabled" @click="imgRemove(k)"></i>
       </div>
     </div>
     <slot name="endSlot"></slot>
     <picture-previewer
       :visible.sync="dialogImageVisible"
       :src="imageUrls"
       :current="currentImage"
     />
   </div>
 </template>
 <script>
 import Utils from "../../src/utils/commonUtils";
 export default {
   name: "ImageUpload",
   props: {
     active: { type: String, default: "/api/file/upload" },
     accept: { type: String, default: "" },
     limitNum: { type: Number, default: 9 },
     size: { type: Number, default: 10 },
     prev: { type: Boolean, default: true },
     disabled: { type: Boolean, default: false },
     value: { type: Array, default: () => [] }
   },
   data() {
     return {
       fileLoading: false,
       dialogImageVisible: false,
       dialogImageUrl: "",
       currentImage: 0,
       fileLists: [],
       messageInfo: ""
     };
   },
   computed: {
     imageUrls: function () {
       return this.fileLists.map(o => o.url);
     }
   },
   methods: {
     async validateImage(file) {
       const isJPEG = file.type === "image/jpeg";
       const isJPG = file.type === "image/jpg";
       const isPNG = file.type === "image/png";
       const isBMP = file.type === "image/bmp";
       const isLtSize = file.size / 1024 / 1024 < this.size;
       if (!(isJPEG || isJPG || isPNG || isBMP)) {
         return {
           status: false,
           message: `上傳圖片必須是${this.accept}格式!`
         };
       }
       if (!isLtSize) {
         return {
           status: false,
           message: "上傳圖片大小不能超過 " + this.size + " MB!"
         };
       }
       return { status: true, message: "" };
     },
     // 選擇文件
     selectFile() {
       this.$refs.fileInput.value = null; // 置空,防止刪除后無法再次選擇
       this.$refs.fileInput.click();
       return true;
     },
     // 文件選取之后·
     async fileChange(el) {
       const file = [...el.target.files][0];
       let { status, message } = await this.validateImage(file);
       if (status) {
         this.fileLoading = true;
         await this.customHttpRequest(file);
       } else {
         this.$message.error(message);
         return false;
       }
     },
     // 上傳
     async customHttpRequest(file) {
       try {
         let fData = Utils.createUploadForm(file);
         let {
           data: { data, status, message }
         } = await this.$http.post(this.active, fData.formData, fData.config);
         if (status) {
           this.fileLists.unshift(data);
           this.$emit("success", data);
         } else {
           this.$message.error(message);
           this.$emit("error");
         }
       } finally {
         this.fileLoading = false;
       }
     },
     imgPreview(file, k) {
       this.dialogImageUrl = file.url;
       this.dialogImageVisible = true;
       this.currentImage = k;
     },
     imgRemove(index) {
       this.fileLists.splice(index, 1);
       this.$emit("input", this.fileLists);
       this.$emit("change", this.fileLists);
       this.$emit("blur", this.fileLists);
     },
     horizontalRolling() {
       if (this.$refs["pictures"].clientWidth < this.$refs["pictures"].scrollWidth) {
         this.messageInfo = "滾動滾輪查看所有信息";
       } else {
         this.messageInfo = "";
       }
       this.$refs["pictures"].addEventListener("mousewheel", this.$_scrollEvent);
       this.$once("hook:beforeDestroy", () => {
         this.$refs["pictures"].removeEventListener("mousewheel", this.$_scrollEvent);
       });
     },
     $_scrollEvent(e) {
       let left = this.$refs["pictures"].scrollLeft;
       this.$refs["pictures"].scrollLeft = e.deltaY > 0 ? left + 40 : left - 40;
     }
   },
   watch: {
     value: {
       deep: true,
       immediate: true,
       handler: function () {
         this.fileLists = typeof this.value === "string" ? JSON.parse(this.value) : this.value;
         if (!this.fileLists) this.fileLists = [];
       }
     },
     fileLists: {
       deep: true,
       immediate: false,
       handler: function () {
         if (this.value && this.value.length > this.limitNum) {
           this.$message.warning(`最多可以上傳【 ${this.limitNum} 】張圖片!!`);
         }
         this.$emit("input", this.fileLists);
         this.$emit("change", this.fileLists);
       }
     }
   }
 };
 </script>

因?yàn)槭莾?nèi)部項(xiàng)目,所以上傳方法還是使用的實(shí)例上的 axios 方法來發(fā)送上傳請求的;在獨(dú)立組件庫中依然應(yīng)該通過 props 的方式傳遞項(xiàng)目中定義的 http 請求方法。

組件接收一個(gè)最大張數(shù)限制 limitNum 和文件大小限制 size,以及預(yù)覽控制 prev 和禁用狀態(tài) disabled。

在選擇文件之后會立即上傳、點(diǎn)擊已上傳文件則是預(yù)覽當(dāng)前文件;當(dāng)前內(nèi)部也依賴了 ElementUI 的 Message 組件,用來顯示提示信息。

在預(yù)覽區(qū)域前后也增加了一個(gè)插槽,用來插入開發(fā)者需要的其他信息。

在整個(gè)組件的 Dom 節(jié)點(diǎn)上,會添加一個(gè)鼠標(biāo)的 mouseenter 事件,當(dāng)鼠標(biāo)在組件內(nèi)部的時(shí)候,則計(jì)算內(nèi)部的縮略圖區(qū)域與外層節(jié)點(diǎn)的大小進(jìn)行比較,如果大于外層父節(jié)點(diǎn)的寬度的話,則提示用戶通過鼠標(biāo)滾輪來控制縮略圖區(qū)域的滾動。

3. 后記

整個(gè)組件雖然可以滿足當(dāng)時(shí)的系統(tǒng)的一個(gè)需求,但是仔細(xì)研究代碼的話會發(fā)現(xiàn)依然有很多細(xì)節(jié)的地方需要修復(fù)。例如:

  • 組件的 mouseenter 事件,每次被觸發(fā)時(shí)都會給 dom 添加一個(gè)鼠標(biāo)監(jiān)聽事件,而沒有在鼠標(biāo)移出時(shí)及時(shí)銷毀監(jiān)聽
  • 沒有增加自定義 http 配置
  • 沒有控制預(yù)覽組件的配置項(xiàng)
  • 縮略圖區(qū)域沒有尺寸控制

等等一系列的問題,所以我們在抽離組件、公共邏輯的時(shí)候,還是需要盡可能的保留以后擴(kuò)展的可能性,減少與外界邏輯或者業(yè)務(wù)的關(guān)聯(lián)。

以上就是ElementUI修改實(shí)現(xiàn)更好用圖片上傳預(yù)覽組件的詳細(xì)內(nèi)容,更多關(guān)于ElementUI圖片上傳預(yù)覽的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • vue3的基本使用方法詳細(xì)教程

    vue3的基本使用方法詳細(xì)教程

    這篇文章主要介紹了vue3的基本使用方法,結(jié)合實(shí)例形式詳細(xì)分析了vue3功能、組件、生命周期、TypeScript結(jié)合運(yùn)用等相關(guān)概念與使用方法,需要的朋友可以參考下
    2023-06-06
  • vue3+ts+vite中“@“路徑失效的解決辦法

    vue3+ts+vite中“@“路徑失效的解決辦法

    這篇文章主要介紹了vue3+ts+vite中“@“路徑失效的解決辦法,在使用vite腳手架生成項(xiàng)目時(shí),解決引入路徑失敗的錯(cuò)誤,可以按照本文介紹的步驟操作,需要的朋友可以參考下
    2024-11-11
  • easycom模式開發(fā)UNI-APP組件調(diào)用必須掌握的實(shí)用技巧

    easycom模式開發(fā)UNI-APP組件調(diào)用必須掌握的實(shí)用技巧

    uni-app基于VUE開發(fā),通常組件的使用都是先安裝,然后全局或者局部引入,注冊,今天通過本文給大家分享easycom模式開發(fā)UNI-APP組件調(diào)用必須掌握的實(shí)用技巧,需要的朋友一起看看吧
    2021-08-08
  • vscode下的vue文件格式化問題

    vscode下的vue文件格式化問題

    這篇文章主要介紹了vscode下的vue文件格式化問題,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2018-11-11
  • 3種vue組件的書寫形式

    3種vue組件的書寫形式

    這篇文章主要為大家詳細(xì)介紹了3種vue組件的書寫形式,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-11-11
  • vue中使用js-xlsx導(dǎo)出excel的實(shí)現(xiàn)方法

    vue中使用js-xlsx導(dǎo)出excel的實(shí)現(xiàn)方法

    本文主要介紹了vue中使用js-xlsx導(dǎo)出excel的實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • vue刷新和tab切換實(shí)例

    vue刷新和tab切換實(shí)例

    下面小編就為大家分享一篇vue刷新和tab切換實(shí)例,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-02-02
  • 關(guān)于vue-router的使用及實(shí)現(xiàn)原理

    關(guān)于vue-router的使用及實(shí)現(xiàn)原理

    這篇文章主要介紹了關(guān)于vue-router的使用及實(shí)現(xiàn)原理,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-06-06
  • Vue項(xiàng)目中封裝組件的簡單步驟記錄

    Vue項(xiàng)目中封裝組件的簡單步驟記錄

    眾所周知組件(component)是vue.js最強(qiáng)大的功能之一,它可以實(shí)現(xiàn)功能的復(fù)用,以及對其他邏輯的解耦,下面這篇文章主要給大家介紹了關(guān)于Vue項(xiàng)目中封裝組件的相關(guān)資料,需要的朋友可以參考下
    2021-09-09
  • Vue.js實(shí)現(xiàn)tab切換效果

    Vue.js實(shí)現(xiàn)tab切換效果

    這篇文章主要為大家詳細(xì)介紹了Vue.js實(shí)現(xiàn)tab切換效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-07-07

最新評論

江达县| 仙桃市| 静宁县| 竹北市| 禄丰县| 沙洋县| 新巴尔虎左旗| 慈溪市| 固原市| 青阳县| 永寿县| 龙岩市| 丹巴县| 鹰潭市| 潮安县| 祁连县| 襄汾县| 汤原县| 揭东县| 昌江| 克什克腾旗| 三江| 尚义县| 通河县| 沁阳市| 襄樊市| 盐亭县| 成都市| 错那县| 独山县| 新兴县| 江口县| 宁波市| 彰武县| 和顺县| 岳西县| 准格尔旗| 富蕴县| 桃江县| 潮州市| 柳林县|