js 写一个前端图片查看器

30 篇文章 3 订阅
19 篇文章 0 订阅

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;
	            }
	        }
	    }
	}
}
  • 7
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 首先,需要准备好Vue和axios,然后创建一个Vue实例,在实例中定义一个data函数,用于存储分页查询的信息,包括当前页数、每页的数量和总数量等。在created函数中,调用axios来发送请求,获取分页数据。在mounted函数中,初始化分页器。在methods函数中,添加分页器的处理函数,实现点击分页器时触发axios来获取分页数据。 ### 回答2: Vue.js是一种用于构建用户界面的JavaScript框架。它具有简单易用、高效灵活的特点,因此非常适合用来开发前端分页查询程序。 首先,我们需要安装Vue.js和Vue Router插件。然后创建一个Vue实例,并在该实例中定义一个组件用于处理分页查询功能。 在组件中,我们可以使用Vue的响应式数据来存储查询结果和当前页码。我们还可以使用计算属性来根据总记录数和每页显示的数据量计算总页数。 接下来,我们需要在模板中定义一个表格来显示查询结果。可以使用v-for指令来遍历查询结果数组,并显示每条记录的相关信息。 为了实现分页功能,我们可以添加两个按钮或链接,一个用于切换到上一页,另一个用于切换到下一页。当点击按钮时,我们可以调用方法来更新当前页码,并重新查询数据。 为了实现数据的异步加载和渲染,我们可以使用Axios或Fetch等工具来发送HTTP请求,并接收服务器返回的数据。 最后,我们可以在Vue实例的mounted钩子函数中调用查询方法,来初始化数据并显示第一页的查询结果。 整个过程中,我们可以使用Vue的生命周期钩子函数来管理组件的生命周期,以便在适当的时候加载数据、监听事件、更新状态等。 通过以上步骤,我们就可以构建一个基本的Vue前端分页查询程序了。当用户输入查询条件并点击查询按钮时,程序将发送请求到后端服务器并获取分页查询结果,然后将结果显示在前端界面中。用户还可以通过按钮或链接来切换不同的页码,以便查看更多的查询结果。 ### 回答3: Vue是一个用于构建用户界面的渐进式JavaScript框架。使用Vue可以轻松地构建交互式的前端应用程序。下面是一个使用Vue实现前端分页查询的示例程序。 1. 在HTML文件中引入Vue和axios,axios是一个用于进行HTTP请求的库。 ```html <html> <head> <title>前端分页查询</title> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script> </head> <body> <div id="app"> <h1>前端分页查询</h1> <table> <thead> <tr> <th>ID</th> <th>Name</th> <th>Age</th> </tr> </thead> <tbody> <tr v-for="person in persons" :key="person.id"> <td>{{person.id}}</td> <td>{{person.name}}</td> <td>{{person.age}}</td> </tr> </tbody> </table> <div> <button @click="previousPage">上一页</button> <span>{{currentPage}}</span> <button @click="nextPage">下一页</button> </div> </div> <script src="script.js"></script> </body> </html> ``` 2. 在JavaScript文件中编Vue实例和相关的方法。 ```javascript let app = new Vue({ el: '#app', data: { currentPage: 1, // 当前页码 pageSize: 10, // 每页显示的记录数 totalRecords: 0, // 总记录数 persons: [] // 查询结果 }, mounted() { this.loadData(); // 初始化时加载数据 }, methods: { loadData() { let startIndex = (this.currentPage - 1) * this.pageSize; // 计算查询起始位置 let url = `https://example.com/api/persons?startIndex=${startIndex}&pageSize=${this.pageSize}`; axios.get(url) .then(response => { this.persons = response.data; // 将查询结果赋值给persons数组 this.totalRecords = response.headers['x-total-count']; // 获取总记录数 }) .catch(error => { console.log(error); }); }, previousPage() { if (this.currentPage > 1) { this.currentPage--; this.loadData(); // 加载上一页数据 } }, nextPage() { let totalPages = Math.ceil(this.totalRecords / this.pageSize); if (this.currentPage < totalPages) { this.currentPage++; this.loadData(); // 加载下一页数据 } } } }); ``` 以上示例程序实现了一个简单的前端分页查询功能。用户可以点击“上一页”和“下一页”按钮来切换分页,并且查询结果会根据当前页码和每页记录数进行动态加载。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值