zhgdyun/src/components/ImgReview.vue

323 lines
8.6 KiB
Vue
Raw Normal View History

2022-06-08 14:51:11 +08:00
<template>
<div
class="img-review-wrapper"
v-show="imgReviewVisible"
@click.self="closeImgReview"
@mousewheel.prevent="rollImg()"
>
<!-- 顶部信息栏 & 工具栏 -->
<div class="tip-wrapper" v-if="imgReviewVisible">
<div class="name" :title="activeFileName + activeExtendName">{{ activeFileName }}.{{ activeExtendName }}</div>
<div class="opera-btn-group">
<el-input-number v-model="inputActiveIndex" :min="1" :max="imgReviewList.length" size="mini"></el-input-number>
<span class="split-line">/</span>{{ imgReviewList.length }}
</div>
<div class="tool-wrapper">
<i class="item el-icon-refresh-right" title="向右旋转" @click="rotateImg"></i>
<a
class="item download-link"
target="_blank"
:href="activeDownloadLink"
:download="activeFileName + '.' + activeExtendName"
>
<i class="el-icon-download" title="保存到本地"></i>
</a>
<el-tooltip effect="dark" placement="bottom">
<div slot="content">
操作提示<br />
点击图片以外的区域可退出查看<br />
按Esc键可退出查看<br />
鼠标滚轮可放大缩小图片
</div>
<div class="item text-wrapper">
<span class="text">操作提示</span>
<i class="el-icon-question"></i>
</div>
</el-tooltip>
</div>
</div>
<!-- 大图查看 -->
<img
class="img-large"
ref="imgLarge"
v-for="(item, index) in imgReviewList"
:key="index"
:src="item.fileUrl"
v-show="index === activeIndex"
/>
<!-- 左右切换图标 -->
<i class="pre-icon el-icon-arrow-left" title="上一张" v-show="activeIndex > 0" @click.stop="activeIndex--"></i>
<i
class="next-icon el-icon-arrow-right"
title="下一张"
v-show="activeIndex < imgReviewList.length - 1"
@click.stop="activeIndex++"
></i>
<!-- 底部显示放大缩小比例 -->
<div class="zoom-bar">
<el-slider
v-model="imgZoom"
:min="imgZoomMin"
:max="imgZoomMax"
:format-tooltip="formatZoom"
@input="changeZoom"
></el-slider>
<div class="zoom-count">{{ imgZoom }}%</div>
</div>
</div>
</template>
<script>
export default {
name: 'ImgReview',
data() {
return {
rotate: 0, // 旋转角度
activeIndex: 0, // 当前图片索引 从 0 开始
imgZoom: 40, // 图片缩放比例
imgZoomMin: 1, // 图片缩放最小比例
imgZoomMax: 200 // 图片缩放最大比例
}
},
computed: {
// 图片查看组件是否显示
imgReviewVisible() {
return this.$store.state.imgReview.imgReviewVisible
},
// 图片列表
imgReviewList() {
return this.$store.state.imgReview.imgReviewList
},
// 默认显示的图片索引 从 0 开始
defaultActiveIndex() {
return this.$store.state.imgReview.defaultActiveIndex
},
// 当前显示的图片名称
activeFileName() {
return this.imgReviewList[this.activeIndex].fileName
},
// 当前显示的图片扩展名
activeExtendName() {
return this.imgReviewList[this.activeIndex].extendName
},
// 对用户而言 显示的图片索引 从 1 开始 顶部栏输入框控制此值变化
inputActiveIndex: {
get() {
return this.activeIndex + 1
},
set(value) {
this.activeIndex = value - 1
}
},
// 当前显示的图片下载链接
activeDownloadLink() {
return this.imgReviewList[this.activeIndex].downloadLink
}
},
watch: {
// 监听 图片查看组件 显隐状态变化
imgReviewVisible(val) {
let body = document.querySelector('body')
if (val) {
this.activeIndex = this.defaultActiveIndex
// 挂在body下防止组件元素有样式transform而使position: fixed失效
body.appendChild(this.$el)
body.style.overflow = 'hidden'
// 添加键盘Esc事件
this.$nextTick(() => {
document.addEventListener('keyup', (e) => {
if (e.keyCode === 27) {
this.closeImgReview()
}
})
})
this.$nextTick(() => {
this.$refs.imgLarge[this.activeIndex].style.zoom = '40%'
})
} else {
body.style.overflow = 'auto'
document.removeEventListener('keyup', (e) => {
if (e.keyCode === 27) {
this.closeImgReview()
}
})
}
},
// 监听 图片索引变化
activeIndex(newValue) {
this.rotate = 0
this.$nextTick(() => {
if (this.$refs.imgLarge[newValue].style.zoom) {
this.imgZoom = Number(this.$refs.imgLarge[newValue].style.zoom.split('%')[0])
} else {
this.$refs.imgLarge[newValue].style.zoom = '40%'
this.imgZoom = 40
}
})
}
},
methods: {
// 关闭图片预览
closeImgReview() {
this.$store.commit('setImgReviewData', { imgReviewVisible: false })
this.rotate = 0
this.$refs.imgLarge[this.activeIndex].style.transform = `rotate(${this.rotate}deg)`
},
// 格式化缩放数字 显示图片缩放比例
formatZoom(value) {
return value + '%'
},
// 图片缩放改变事件
changeZoom(value) {
if (this.$refs.imgLarge) {
this.$refs.imgLarge[this.activeIndex].style.zoom = value + '%'
}
},
// 缩放图片
rollImg() {
let zoom = parseInt(this.$refs.imgLarge[this.activeIndex].style.zoom) || 100
zoom += event.wheelDelta / 12
if (zoom >= this.imgZoomMin && zoom < this.imgZoomMax) {
this.imgZoom = zoom
this.$refs.imgLarge[this.activeIndex].style.zoom = zoom + '%'
}
return false
},
// 旋转图片
rotateImg() {
this.rotate += 90
this.$refs.imgLarge[this.activeIndex].style.transform = `rotate(${this.rotate}deg)`
}
}
}
</script>
<style lang="stylus" scoped>
@import '../assets/style/varibles.styl'
.img-review-wrapper
position fixed
top 0
right 0
bottom 0
left 0
overflow auto
width 100%
height 100%
z-index 2010
text-align center
display flex
align-items center
animation imgReviewAnimation 0.3s
-webkit-animation imgReviewAnimation 0.3s /* Safari and Chrome */
animation-iteration-count 0.3
-webkit-animation-iteration-count 0.3
animation-fill-mode forwards
-webkit-animation-fill-mode forwards /* Safari 和 Chrome */
@keyframes imgReviewAnimation
0%
background transparent
100%
background rgba(0, 0, 0, 0.8)
@keyframes imgReviewAnimation
0%
background transparent
100%
background rgba(0, 0, 0, 0.8)
.tip-wrapper
position fixed
top 0
left 0
z-index 2011
background rgba(0, 0, 0, 0.5)
padding 0 48px
width calc(100% - 96px)
height 48px
line-height 48px
color #fff
font-size 16px
display flex
justify-content space-between
.name
flex 1
padding-right 16px
text-align left
overflow hidden
text-overflow ellipsis
white-space nowrap
.opera-btn-group
width 100px
display flex
>>> .el-input-number
width 40px
.el-input-number__decrease,
.el-input-number__increase
display none
.el-input__inner
margin-top 14px
background rgba(0, 0, 0, 0.5)
height 20px
line-height 20px
padding 0
font-size 16px
color #fff
.split-line
margin 0 8px
.tool-wrapper
flex 1
display flex
justify-content flex-end
.item
margin-left 16px
cursor pointer
&:hover
opacity 0.7
.el-icon-refresh-right
line-height 48px
font-size 18px
.download-link
color inherit
font-size 18px
.text-wrapper
margin-left 32px
.text
margin-right 8px
.img-large
margin 0 auto
transition transform 0.5s
-webkit-transition transform 0.5s /* Safari */
.pre-icon,
.next-icon
font-size 60px
color #fff
position fixed
top 50%
cursor pointer
&:hover
opacity 0.7
.pre-icon
left 64px
.next-icon
right 64px
.zoom-bar
position fixed
right 0
bottom 20px
left 0
margin 0 auto
width 600px
display flex
>>> .el-slider
flex 1
.el-slider__bar
background $PrimaryText
.el-slider__button
border-color $PrimaryText
.zoom-count
width 60px
height 38px
line-height 38px
text-align right
color #fff
</style>