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;
}
}
}
}
}