废话不多说,先看东西
这是详情,支持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">
<img @click="toDetailPage(index)" :src="item" v-for="(item,index) in targetImages" :key="index"
:class="currentActiveIndex===index?'iv-detail-list-item iv-detail-list-item-active':'iv-detail-list-item'">
</div>
</div>
<div class="original-view" v-if="isOriginalIvShow">
<div class="image-container">
<img :src="detailSrc">
<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();
},
样式代码就不贴了,自己写吧。
做这种东西,看完分析应该就可以自己写出来了。不能完全了白嫖,嫖思想就行了,哈哈。
相关推荐
本文和表情组件一样,只是一个模块,作为摸鱼君的模块功能,直接使用。
相关的内容