「前端」有空来撸一只图片浏览器?power by vue.js
废话不多说,先看东西
支持1~9宫格
左右可以切换,点击底部的列表也可以切换。
点击中间收起,顶部可以旋转,查看原图等功能。
这个其实就是我们摸鱼模块里的图片预览组件。
接下来,我们就是要写这么个玩意。
环境
这个是nuxt.js项目+element-ui
element-ui 主要是用了几个图标,也没使用啥。
所以还是靠纯手工撸码吧
分析
这个控件,有三个状态
- 普通的预览状态
- 详情浏览状态
- 原图查看状态
第一和第二个状态互斥,第二和第三个状态可以共存
所以我们在div结构上可以分三个。
通过状态来控制显示和隐藏即可。
再细分:
普通预览状态
这个没有难度,就是图片渲染,然后根据不同的图片数量控制大小样式之类的。而类名可以动态根据图片的数量生成。
共同样式的进行抽取即可。
详情页面
- 收起功能,其实就是改变状态,控制显示即可。
- 查看大图,就是显示当前的图片的原图即可,不改变大小。写个样式,显示一下就可以了。
- 左右旋转,旋转我们通过修改translate里的rotate即可,再通过计算一下偏移量,重新修正大小,并且动态改变容器的大小。
- 左右切换,本质上就是移动下标,然后更新数据源。这里要注意的是界限和重置旋转后的状态。
以上分析就可以完成这个功能了。在摸鱼君的课程里不会详细讲此课程,这只是作为了个组件模块讲解,跟表情控制面板一样。
在摸鱼君课程中,直接使用该控件。
布局代码
先看看整体的布局代码
<div id=”image-viewer”> <div class=”preview clear-fix” v-show=”isPreview”> <!–遍历内容显示–> <div :class=”‘image-item image-item-‘+targetImages.length” v-for=”(item,index) in targetImages” :key=”index”> <img :src=”item” alt=”image” @click=”toDetailPage(index)”> </div> </div> <div class=”detail” v-show=”!isPreview”> <!–顶部的控制栏–> <div class=”iv-viewer-action-bar”> <span class=”el-icon-zoom-out” @click=”toPreviewPage”>收起</span> <span class=”el-icon-search” @click=”showOriginalIv”>查看大图</span> <span class=”el-icon-refresh-left” @click=”doRotate(-1)”>向左旋转</span> <span class=”el-icon-refresh-right” @click=”doRotate(1)”>向右旋转</span> </div> <div class=”iv-detail-part” id=”iv-detail-part”> <img id=”detail-iv” :src=”detailSrc” @click=”toPreviewPage”> <div id=”iv-left-arrow” @click=”leftMove”></div> <div id=”iv-right-arrow” @click=”rightMove”></div> </div> <div class=”iv-list-part”> </div> </div> <div class=”original-view” v-if=”isOriginalIvShow”> <div class=”image-container”> <span class=”image-close” @click=”closeOriginalIv”>X</span> </div> </div> </div>
这里是三部分的内容了
- preview 预览部分
- detail 详情部分
- original 原图显示部分
data() { return { image1: [‘/images/1.png’], images2: [‘/images/1.png’, ‘/images/2.png’], images3: [‘/images/1.png’, ‘/images/2.png’, ‘/images/3.jpeg’], images4: [‘/images/1.png’, ‘/images/2.png’, ‘/images/3.jpeg’, ‘/images/4.jpeg’], images5: [‘/images/1.png’, ‘/images/2.png’, ‘/images/3.jpeg’, ‘/images/4.jpeg’, ‘/images/5.jpeg’], images6: [‘/images/1.png’, ‘/images/2.png’, ‘/images/3.jpeg’, ‘/images/4.jpeg’, ‘/images/5.jpeg’, ‘/images/6.jpeg’], images7: [‘/images/1.png’, ‘/images/2.png’, ‘/images/3.jpeg’, ‘/images/4.jpeg’, ‘/images/5.jpeg’, ‘/images/6.jpeg’, ‘/images/7.jpeg’], images8: [‘/images/1.png’, ‘/images/2.png’, ‘/images/3.jpeg’, ‘/images/4.jpeg’, ‘/images/5.jpeg’, ‘/images/6.jpeg’, ‘/images/7.jpeg’, ‘/images/8.jpeg’], images9: [‘/images/1.png’, ‘/images/2.png’, ‘/images/3.jpeg’, ‘/images/4.jpeg’, ‘/images/5.jpeg’, ‘/images/6.jpeg’, ‘/images/7.jpeg’, ‘/images/8.jpeg’, ‘/images/9.png’], targetImages: [], detailSrc: ”, isPreview: true, currentActiveIndex: 0, isOriginalIvShow: false, currentDeg: 0, originalWidth: 0, originalHeight: 0 } },
从预览到详情页面
toDetailPage(index) { this.currentActiveIndex = index; this.isPreview = false; this.updateArrowPartVisibility(); this.updateDetailImage();},
旋转
doRotate(direction) { let detailIv = document.getElementById(‘detail-iv’); if (this.currentDeg === 0) { this.originalWidth = detailIv.width; this.originalHeight = detailIv.height; console.log(“this.originalWidth ==> ” + this.originalWidth); console.log(“this.originalHeight ==> ” + this.originalHeight); } if (direction > 0) { //向右转 this.currentDeg += 90; if (this.currentDeg >= 360) { this.currentDeg = 0; } } else { //向左转 this.currentDeg -= 90; if (this.currentDeg <= -360) { this.currentDeg = 0; } } //重新计算高度 let detailIvContainer = document.getElementById(‘iv-detail-part’); //获取当前IV的宽高,然后宽高对调,调整容器 let ivWidth = detailIv.width; let ivHeight = detailIv.height; let ctWidth = detailIvContainer.offsetWidth; if (this.currentDeg === 90 || this.currentDeg === -270) { //横向 //如果高度大于容器的宽度,那么需要对图片进行缩放,并且计算宽高 if (ivHeight > ctWidth) { detailIv.style.height = ctWidth + ‘px’; ivHeight = detailIv.height; ivWidth = detailIv.width; } let targetTranslate = (ivWidth – ivHeight) / 2 + 10; detailIv.style.transform = ‘rotate(‘ + this.currentDeg + ‘deg) translate(‘ + targetTranslate + ‘px, 0)’; detailIvContainer.style.height = ivWidth + 10 + ‘px’; } else if (this.currentDeg === 180) { //宽高复原 detailIv.style.height = this.originalHeight + ‘px’; ivHeight = detailIv.height; ivWidth = detailIv.width; //纵向,相反 detailIv.style.transform = ‘rotate(‘ + this.currentDeg + ‘deg)’; detailIvContainer.style.height = ivHeight + 10 + ‘px’; } else if (this.currentDeg === 270 || this.currentDeg === -90) { //横向 if (ivHeight > ctWidth) { detailIv.style.height = ctWidth + ‘px’; ivHeight = detailIv.height; ivWidth = detailIv.width; } detailIvContainer.style.height = ivWidth + 10 + ‘px’; let targetTranslate = (ivHeight – ivWidth) / 2 – 10; console.log(“targetTranslate ==> ” + targetTranslate); detailIv.style.transform = ‘rotate(‘ + this.currentDeg + ‘deg) translate(‘ + targetTranslate + ‘px, 0)’; } else { detailIv.style.height = this.originalHeight + ‘px’; ivHeight = detailIv.height; ivWidth = detailIv.width; detailIv.style.transform = ‘rotate(‘ + this.currentDeg + ‘deg)’; detailIvContainer.style.height = ivHeight + 10 + ‘px’; }},
控制左右切换的边界
updateArrowPartVisibility() { //如果是第0个,左边不显示 //如果是最后一个,右边不显示 if (this.currentActiveIndex === 0) { document.getElementById(‘iv-left-arrow’).style.display = ‘none’; } else { document.getElementById(‘iv-left-arrow’).style.display = ‘block’; } if (this.currentActiveIndex === this.targetImages.length – 1) { document.getElementById(‘iv-right-arrow’).style.display = ‘none’; } else { document.getElementById(‘iv-right-arrow’).style.display = ‘block’; }},
更新图片的显示
updateDetailImage() { this.detailSrc = this.targetImages[this.currentActiveIndex]; let detailIv = document.getElementById(‘detail-iv’); let detailIvContainer = document.getElementById(‘iv-detail-part’); detailIvContainer.style.height = ”; detailIv.style.transform = ”; detailIv.style.height = ”; this.currentDeg = 0; }
显示原图
showOriginalIv() { this.isOriginalIvShow = true; },
关闭原图
closeOriginalIv() { this.isOriginalIvShow = false; },
左右切换
leftMove() { this.currentActiveIndex–; if (this.currentActiveIndex < 0) { this.currentActiveIndex = 0; } this.updateArrowPartVisibility(); this.updateDetailImage(); }, rightMove() { this.currentActiveIndex++; if (this.currentActiveIndex > this.targetImages.length – 1) { this.currentActiveIndex = this.targetImages.length – 1; } this.updateArrowPartVisibility(); this.updateDetailImage(); },
样式代码就不贴了,自己写吧。
做这种东西,看完分析应该就可以自己写出来了。不能完全了白嫖,嫖思想就行了,哈哈。
相关推荐
本文和表情组件一样,只是一个模块,作为摸鱼君的模块功能,直接使用。
相关的内容
JavaWeb微服务项目-摸鱼君
原创文章,作者:starterknow,如若转载,请注明出处:https://www.starterknow.com/126797.html