js 寫一個前端圖片查看器

1. 前言

網上已經有不少成熟的圖片查看器插件,如果是單純想要點擊圖片放大預覽的話,可以直接使用插件。例如viewerjs

但是,當打開圖片後還需要對圖片進行一些像刪除、下載、標記等業務層面上的操作,使用插件就顯得不那麼便捷,於是決定自己簡單寫個圖片查看器

2. 設計思路

項目中用的是vue+iview,於是使用Modal彈窗組件做爲播放器的盒子,考慮需要用到的基本功能有:放大縮小、監聽鼠標滾輪放大縮小、拖拽、全屏查看、查看上/下一張、雙擊圖片回到初始大小和初始位置

3. 完成效果

在這裏插入圖片描述
4. 代碼思路

html部分:

<Modal
	id="picture_viewer_modal"
	v-model="visible"
	:mask-closable = "false"
	@on-cancel="cancel()"
	footer-hide
	width="70%"
	:fullscreen="fullscreen"
>
	<div class="wrap">
		<p class="num_tip">第 {{index+1}}/{{picArr.length}} 張</p>
		
		<!-- 查看圖片的盒子 -->
		<div id="father" class="box">
		    <img id="box" class="img_max img_auto" @dblclick="getDefault()" :src="row.src">
		    <!-- 查看上一張 -->
		    <span class="next_btn btn_left" @click="left()"></span>
		    <!-- 查看下一張 -->
		    <span class="next_btn btn_right" @click="right()"></span>
		</div>
		
		<!-- 按鈕條 -->
		<div class="tool_bar">
		    <!-- 裁剪 -->
		    <span class="tool_btn btn_1" @click="cutPic()"></span>
		    <!-- 全屏 -->
		    <span class="tool_btn btn_2" @click="fullScreen()"></span>
		    <!-- 放大 -->
		    <span class="tool_btn btn_3" @click="big()"></span>
		    <!-- 縮小 -->
		    <span class="tool_btn btn_4" @click="small()"></span>
		    <!-- 下載 -->
		    <span class="tool_btn btn_5" @click="download()"></span>
	       <!-- 選中 -->
	       <span class="tool_btn btn_8" @click="choose()"></span>
	       <!-- 刪除 -->
	       <span class="tool_btn btn_9" @click="del(row.id)"></span>
	   </div>
	</div>
</Modal>

js部分:

props: {
    picList:Array,
    rowData:Object
},
data() {
    return {
    	//彈窗顯隱
        visible: false,
        //當前查看的圖片
        row: {},
        //當前查看的圖片在數組中的位置
        index: 0,
        //所有圖片
        picArr: [],
        //是否全屏
        fullscreen: false,
    };
},
watch: {
	//監聽彈窗打開事件
    modal(val) {
        this.visible = val;
        if(val){
            this.init();
            this.getObj();
        }
    },
},
mounted(){
    this.move(); 
},
methods: {
     /**
     * 打開彈窗後,獲取傳入彈窗組件的數據
     */
	 getObj(){
         this.row = this.rowData.row;
         this.index = this.rowData.index;
         this.picArr = this.picList;
     },
     /**
      * 初始化
      */
     init(){
         this.fullscreen = false;
         //重新打開後圖片要重置回默認大小和居中
         this.getDefault();
     },
     /**
      * 雙擊圖片恢復默認大小、位置
      */
     getDefault(){
         var image = document.getElementById("box");
         image.classList.add('img_max');
         image.classList.add('img_auto');
         box.style.left = '50%';
         box.style.top = '50%';
         box.style.transform = 'translate(-50%,-50%)';
     },
     /**
      * 拖拽移動
      */
     move(){
         var thiz = this;
         thiz.$nextTick(() => {
             var box = document.getElementById("box");
             var fa = document.getElementById('father');
             // 圖片移動效果
             box.onmousedown=function(ev) {
                 var oEvent = ev;
                 // 瀏覽器有一些圖片的默認事件,這裏要阻止
                 oEvent.preventDefault();
                 var disX = oEvent.clientX - box.offsetLeft;
                 var disY = oEvent.clientY - box.offsetTop;
                 fa.onmousemove=function (ev) {
                     oEvent = ev;
                     oEvent.preventDefault();
                     var x = oEvent.clientX - disX;
                     var y = oEvent.clientY - disY;

                     // 圖形移動的邊界判斷
                     // x = x <= 0 ? 0 : x;
                     // x = x >= fa.offsetWidth-box.offsetWidth ? fa.offsetWidth-box.offsetWidth : x;
                     // y = y <= 0 ? 0 : y;
                     // y = y >= fa.offsetHeight-box.offsetHeight ? fa.offsetHeight-box.offsetHeight : y;
                     box.style.left = x + 'px';
                     box.style.top = y + 'px';
                     //取消居中效果
                     // box.style.transform = 'translate(0,0)';
                 };
                 // 圖形移出父盒子取消移動事件,防止移動過快觸發鼠標移出事件,導致鼠標彈起事件失效
                 fa.onmouseleave = function () {
                     fa.onmousemove = null;
                     fa.onmouseup = null;
                 };
                 // 鼠標彈起後停止移動
                 fa.onmouseup=function() {
                     fa.onmousemove = null;
                     fa.onmouseup = null;
                 }
             }
             //監聽鼠標滾輪放大縮小
             box.addEventListener("mousewheel", MouseWheelHandler, false);// IE9, Chrome, Safari, Opera
             box.addEventListener("DOMMouseScroll", MouseWheelHandler, false);// Firefox
             function MouseWheelHandler(e) {
                 // cross-browser wheel delta  
                 var e = window.event || e; // old IE support  
                 var delta = Math.max(-1, Math.min(1, (e.wheelDelta || -e.detail)));//IE、Opera、Safari、Chrome  e.wheelDelta,Firefox中  e.detail  判斷是向上還是向下滾動負值delta取-1 正值delta取1  
                 box.height = Math.max(100, Math.min(2500, box.height + (50 * delta)));
                 box.classList.remove('img_max');
                 box.classList.remove('img_auto');
                 return false;
             }
         });
     },
     /**
      * 全屏
      */
     fullScreen(){
     	 //控制彈窗全屏
         this.fullscreen = !this.fullscreen;
         //圖片恢復默認大小、位置
         this.getDefault();
     },
     /**
      * 放大
      */
     big(){
         var image = document.getElementById("box");
         if (image.height <= 2500) {
             image.height = image.height + 40;
         }
         image.classList.remove('img_max');
         image.classList.remove('img_auto');
     },
     /**
      * 縮小
      */
     small(){
         var image = document.getElementById("box");
         if (image.height > 100) {
             image.height = image.height - 40;
         }
         image.classList.remove('img_auto');
     },
     /**
      * 查看上一張
      */
     left(){
         var thiz = this;
         if(thiz.index == 0){
             //如果是第一張,則跳到最後一張
             thiz.index = thiz.picArr.length - 1;
             thiz.row = thiz.picArr[thiz.index];
         }else{
             thiz.index = thiz.index - 1;
             thiz.row = thiz.picArr[thiz.index];
         }
         //查看上下一張的時候,圖片回到初始大小和位置,這裏會閃爍,待優化
         this.getDefault();
     },
     /**
      * 查看下一張
      */
     right(){
         var thiz = this;
         if(thiz.index == thiz.picArr.length-1){
             //如果是最後一張,則跳到第一張
             thiz.index = 0;
             thiz.row = thiz.picArr[thiz.index];
         }else{
             thiz.index = thiz.index + 1;
             thiz.row = thiz.picArr[thiz.index];
         }
         //查看上下一張的時候,圖片回到初始大小和位置,這裏會閃爍,待優化
         this.getDefault();
     },
}

css部分:

//less
@pictureBg: #fff,
@pictureBorder: #fff,
@pictureCloseBg: #fff,
@pictureCloseBorder: #1A82FD,
@pictureClose: #1A82FD,
@pictureBtn1: url('../assets/map/view_image/icon_cut_blue.png')
@pictureBtn2: url('../assets/map/view_image/icon_move_blue.png')
@pictureBtn3: url('../assets/map/view_image/icon_zoom_blue.png')
@pictureBtn4: url('../assets/map/view_image/icon_reduce_blue.png')
@pictureBtn5: url('../assets/map/view_image/icon_download_blue.png')
@pictureBtn6: url('../assets/map/view_image/icon_play_blue.png')
@pictureBtn7: url('../assets/map/view_image/icon_video_blue.png')
@pictureBtn8: url('../assets/map/view_image/icon_chose_blue.png')
@pictureBtn9: url('../assets/map/view_image/icon_delete_blue.png')
@pictureBtnHov1: url('../assets/map/view_image/icon_cut_hov.png')
@pictureBtnHov2: url('../assets/map/view_image/icon_move_hov.png')
@pictureBtnHov3: url('../assets/map/view_image/icon_zoom_hov.png')
@pictureBtnHov4: url('../assets/map/view_image/icon_reduce_hov.png')
@pictureBtnHov5: url('../assets/map/view_image/icon_download_hov.png')
@pictureBtnHov6: url('../assets/map/view_image/icon_play_hov.png')
@pictureBtnHov7: url('../assets/map/view_image/icon_video_hov.png')
@pictureBtnHov8: url('../assets/map/view_image/icon_chose_hov.png')
@pictureBtnHov9: url('../assets/map/view_image/icon_delete_hov.png')
#picture_viewer_modal{
	.ivu-modal{
		//覆蓋modal關閉按鈕樣式
	    .ivu-modal-close{
	        right: -12px;
	        top: -12px;
	        border-radius: 100px;
	        background: @pictureCloseBg;
            border:1px solid @pictureCloseBorder;
	        .ivu-icon-ios-close{
	            font-size: 24px;
	            color: @pictureClose;
	        }
	    }
	    //覆蓋modal彈窗盒子樣式
	    .ivu-modal-content{
	    	background: @pictureBg;
            border:1px solid @pictureBorder;
	        border-radius: 0;
	        .ivu-modal-body{
	            height: 80vh;
	            padding: 35px 15px 0;
	            overflow: hidden;
	        }
	        
	        // 內容樣式
	        .wrap{
	            height: 100%;
	            >.num_tip{
	            	color: @pictureClose;
	                position: absolute;
	                top: 10px;
	                left: 15px;
	                z-index: 9;
	            }
	            //圖片盒子樣式
	            >.box{
	                height: calc(100% - 20px - 1.2vw);
	                position: relative;
	                //展示的圖片樣式
	                >img{
	                    position: absolute;
	                    top: 50%;
	                    left: 50%;
	                    transform: translate(-50%, -50%);
	                    cursor: move;
	                    &.img_auto{
	                        width: auto;
	                        height: auto;
	                    }
	                    &.img_max{
	                        max-height: 100%;
	                        max-width: 100%;
	                    }
	                }
	                //上/下一張按鈕樣式
	                >.next_btn{
	                    display: block;
	                    width: 3vw;
	                    height: 3vw;
	                    position: absolute;
	                    top: 50%;
	                    margin-top: -1.5vw;
	                    cursor: pointer;
	                    transition: all 0.2s;
	                    &.btn_left{
	                        left: 6px;
	                        background: url('../../../assets/map/view_image/btn_left.png') no-repeat;
	                        background-size: 100% 100%;
	                        &:hover{
	                            background: url('../../../assets/map/view_image/btn_left_hov.png') no-repeat;
	                            background-size: 100% 100%;
	                        }
	                    }
	                    &.btn_right{
	                        right: 6px;
	                        background: url('../../../assets/map/view_image/btn_right.png') no-repeat;
	                        background-size: 100% 100%;
	                        &:hover{
	                            background: url('../../../assets/map/view_image/btn_right_hov.png') no-repeat;
	                            background-size: 100% 100%;
	                        }
	                    }
	                }
	            }
	         
	         	//底部工具條樣式
	            >.tool_bar{
	                text-align: center;
	                font-size: 0;
	                position: relative;
	                z-index: 9;
	                .tool_btn{
	                    font-size: 12px;
	                    display: inline-block;
	                    width: 1.2vw;
	                    height: 1.2vw;
	                    margin: 10px 0.8vw;
	                    transition: all 0.2s;
	                    cursor: pointer;
	                }
	                .btn_1{
                        background: @pictureBtn1 no-repeat;
                        background-size: 100% 100%;
                        &:hover{
                            background: @pictureBtnHov1 no-repeat;
                            background-size: 100% 100%;
                        }
                    }
                    .btn_2{
                        background: @pictureBtn2 no-repeat;
                        background-size: 100% 100%;
                        &:hover{
                            background: @pictureBtnHov2 no-repeat;
                            background-size: 100% 100%;
                        }
                    }
                    .btn_3{
                        background: @pictureBtn3 no-repeat;
                        background-size: 100% 100%;
                        &:hover{
                            background: @pictureBtnHov3 no-repeat;
                            background-size: 100% 100%;
                        }
                    }
                    .btn_4{
                        background: @pictureBtn4 no-repeat;
                        background-size: 100% 100%;
                        &:hover{
                            background: @pictureBtnHov4 no-repeat;
                            background-size: 100% 100%;
                        }
                    }
                    .btn_5{
                        background: @pictureBtn5 no-repeat;
                        background-size: 100% 100%;
                        &:hover{
                            background: @pictureBtnHov5 no-repeat;
                            background-size: 100% 100%;
                        }
                    }
                    .btn_6{
                        background: @pictureBtn6 no-repeat;
                        background-size: 100% 100%;
                        &:hover{
                            background: @pictureBtnHov6 no-repeat;
                            background-size: 100% 100%;
                        }
                    }
                    .btn_7{
                        background: @pictureBtn7 no-repeat;
                        background-size: 100% 100%;
                        &:hover{
                            background: @pictureBtnHov7 no-repeat;
                            background-size: 100% 100%;
                        }
                    }
                    .btn_8{
                        background: @pictureBtn8 no-repeat;
                        background-size: 100% 100%;
                        &:hover{
                            background: @pictureBtnHov8 no-repeat;
                            background-size: 100% 100%;
                        }
                    }
                    .btn_9{
                        background: @pictureBtn9 no-repeat;
                        background-size: 100% 100%;
                        &:hover{
                            background: @pictureBtnHov9 no-repeat;
                            background-size: 100% 100%;
                        }
                    }
	            }
	        }
	    }
	
	    //彈窗全屏樣式
	    &.ivu-modal-fullscreen{
	        .ivu-modal-close{
	            right: 0;
	            top: 0;
	        }
	        .ivu-modal-content{
	            .ivu-modal-body{
	                height: 100vh;
	                overflow: hidden;
	            }
	        }
	    }
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章