vue图片点击预览
前言起因:关于聊天框图片点击查看的实现,不如记下,以后好复用手写实现在父组件引入并且传值// 父组件<preview :previewImg="companyPreview"></preview>// 引入import preview from "./preview.vue"// components中注册components:{preview},// 传递的参数compa
·
前言
起因:关于聊天框图片点击查看的实现,不如记下,以后好复用
手写实现
- 在父组件引入并且传值
// 父组件
<preview :previewImg="companyPreview"></preview>
// 引入
import preview from "./preview.vue"
// components中注册
components:{preview},
// 传递的参数
companyPreview:{
imgList: [], // 所有图片数组
index: 0, // 当前点击的图片的索引
infinite: false, // 是否可以循环切换
popup: false // 弹窗的显示隐藏
},
// 图片添加点击事件
```js
// 查看图片
lookPhoto(img){
this.companyPreview.imgList[0]=img
this.companyPreview.popup=true
},
- 子组件中封装操作方法
// 预览组件
<template>
<div v-if="previewImg.popup" class="rlPopup">
<div class="close-big-img" @click="close()">
<em class="font_family icon-close-circle"></em>
</div>
<div class="prev handle-btn" v-if="!isSingle" @click="prev()">
<em class="font_family icon-left-line"></em>
</div>
<div class="next handle-btn" v-if="!isSingle" @click="next()">
<em class="font_family icon-right--line"></em>
</div>
<!--放大缩小旋转-->
<div class="zoom-wrap">
<i @click="handleActions('zoomOut')" class="el-icon-zoom-out"></i>
<i @click="handleActions('zoomIn')" class="el-icon-zoom-in"></i>
<i @click="handleActions('left')" class="el-icon-refresh-left"></i>
<i @click="handleActions('right')" class="el-icon-refresh-right"></i>
</div>
<div class="img-list-wrap">
<div v-for="(img, i) in previewImg.imgList" :key="img">
<img
ref="img"
:src="img"
v-if="i === previewImg.index"
:style="imgStyle"
alt="">
</div>
</div>
</div>
</template>
<script>
export default {
name: 'PreviewImage',
props: {
previewImg: {
type: Object,
default: () => {}
}
},
data() {
return {
transform: {
scale: 1,
degree: 0
}
}
},
computed: { // 计算属性动态响应数据
isSingle() { // 单图片无向左向右
return this.previewImg.imgList.length <= 1
},
isFirst() {
return this.previewImg.index === 0
},
isLast() {
return this.previewImg.index === this.previewImg.imgList.length - 1
},
imgStyle() {
const { scale, degree } = this.transform
const style = {
transform: `scale(${scale}) rotate(${degree}deg)`
}
return style
}
},
methods: {
prev() { // 点击切换上一张
if (this.isFirst && !this.previewImg.infinite) return
if (this.$parent.companyPreview.index > 0) {
const len = this.previewImg.imgList.length
this.$parent.companyPreview.index = (this.$parent.companyPreview.index - 1 + len) % len
this.reset()
}
},
next() { // 点击切换下一张
if (this.isLast && !this.previewImg.infinite) return
if (this.previewImg.imgList.length > this.$parent.companyPreview.index) {
const len = this.previewImg.imgList.length
this.$parent.companyPreview.index = (this.$parent.companyPreview.index + 1) % len
this.reset()
}
},
handleActions(action) { // 放大旋转等操作
const { zoomRate, rotateDeg, enableTransition } = {
zoomRate: 0.2,
rotateDeg: 90,
enableTransition: true
}
const { transform } = this
switch (action) {
case 'zoomOut':
if (transform.scale > 0.2) {
transform.scale = parseFloat((transform.scale - zoomRate).toFixed(3))
}
break
case 'zoomIn':
transform.scale = parseFloat((transform.scale + zoomRate).toFixed(3))
break
case 'left':
transform.degree -= rotateDeg
break
case 'right':
transform.degree += rotateDeg
break
}
transform.enableTransition = enableTransition
},
reset() { // 初始化图片样式
this.transform = {
scale: 1,
degree: 0
}
},
close() { // 父组件隐藏
this.$parent.companyPreview.popup = false
}
}
}
</script>
<style lang="less" scoped>
// 查看大图
.rlPopup { // 全屏遮罩显示
position: fixed;
width: 100%;
height: 100%;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
z-index: 999;
.close-big-img {
position: absolute;
top: 20px;
right: 5%;
z-index: 10000;
em {
cursor: pointer;
color: #ffffff;
font-size: 36px;
}
}
.handle-btn {
position: absolute;
top: 50%;
transform: translateY(-50%);
width: 44px;
height: 44px;
line-height: 38px;
font-size: 24px;
color: #fff;
background-color: #606266;
border-color: #fff;
border-radius: 50%;
cursor: pointer;
text-align: center;
z-index: 10000;
}
.prev {
left: 40px;
}
.next {
right: 40px;
}
.img-list-wrap {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
img {
display: block;
object-fit: scale-down;
transition: all 0.3s;
width: 480px;
height: 320px;
}
}
.zoom-wrap {
position: absolute;
bottom: 16px;
left: 50%;
transform: translateX(-50%);
background-color: #606266;
border-radius: 22px;
z-index: 10000;
width: 222px;
height: 44px;
line-height: 47px;
padding: 0 23px;
i {
color: #ffffff;
cursor: pointer;
font-size: 22px;
margin-right: 25px;
&:last-child {
margin-right: 0;
}
}
}
}
</style>
注意事项
以上所有的em标签无法显示,需要自己改为自己项目里面的图标库所需的按钮
- 携带缩略图
<template>
<div v-if="previewImg.popup" class="rlPopup">
<div class="close-big-img" @click="close()">
<em class="font_family icon-close-circle"></em>
</div>
<div class="prev handle-btn" v-if="!isSingle" @click="prev()">
<em class="font_family icon-left-line"></em>
</div>
<div class="next handle-btn" v-if="!isSingle" @click="next()">
<em class="font_family icon-right--line"></em>
</div>
<!--缩略图-->
<div class="thumb-wrap">
<ul>
<li
v-for="(img, index) in previewImg.imgList"
:key="img"
:class="{ active:previewImg.index === index}"
@click="showCurrent(index)">
<img :src="img">
</li>
</ul>
</div>
<div class="img-list-wrap">
<div v-for="(img, i) in previewImg.imgList" :key="img">
<img
ref="img"
:src="img"
v-if="i === previewImg.index"
:style="imgStyle">
</div>
</div>
</div>
</template>
<script>
export default {
name: 'PreviewImage',
props: {
previewImg: {
type: Object,
default: () => {}
}
},
data() {
return {
transform: {
scale: 1,
degree: 0
}
}
},
computed: {
isSingle() {
return this.previewImg.imgList.length <= 1
},
isFirst() {
return this.previewImg.index === 0
},
isLast() {
return this.previewImg.index === this.previewImg.imgList.length - 1
},
imgStyle() {
const { scale, degree } = this.transform
const style = {
transform: `scale(${scale}) rotate(${degree}deg)`
}
return style
}
},
methods: {
prev() {
if (this.isFirst && !this.previewImg.infinite) return
if (this.$parent.companyPreview.index >= 0) {
const len = this.previewImg.imgList.length
this.$parent.companyPreview.index = (this.$parent.companyPreview.index - 1 + len) % len
this.reset()
}
},
next() {
if (this.isLast && !this.previewImg.infinite) return
if (this.previewImg.imgList.length > this.$parent.companyPreview.index) {
const len = this.previewImg.imgList.length
this.$parent.companyPreview.index = (this.$parent.companyPreview.index + 1) % len
this.reset()
}
},
reset() {
this.transform = {
scale: 1,
degree: 0
}
},
showCurrent(index) {
this.previewImg.index = index
},
close() {
this.$parent.companyPreview.popup = false
}
}
}
</script>
<style lang="less" scoped>
// 查看大图
.rlPopup {
background: rgba(0,0,0,0.7);
.close-big-img {
position: absolute;
top: 20px;
right: 2%;
z-index: 1000;
em {
cursor: pointer;
color: #ffffff;
font-size: 36px;
}
}
.handle-btn {
position: absolute;
top: 50%;
transform: translateY(-50%);
width: 66px;
height: 66px;
line-height: 63px;
color: #fff;
background-color: rgba(0, 0, 0, 0.6);
border-radius: 4px;
cursor: pointer;
text-align: center;
z-index: 10000;
em {
font-size: 50px;
}
}
.prev {
left: 5%;
}
.next {
right: 5%;
}
.img-list-wrap {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
img {
display: block;
object-fit: scale-down;
transition: all 0.3s;
max-width: 800px;
max-height: 600px;
}
}
.thumb-wrap {
position: absolute;
bottom: 2%;
left: 50%;
transform: translateX(-50%);
li {
float: left;
width: 60px;
height: 45px;
border: solid 1px #ececec;
position: relative;
margin-right: 5px;
cursor: pointer;
&:last-child {
margin-right: 0;
}
img {
max-width: 57px;
max-height: 42px;
display: block;
object-fit: scale-down;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
}
.active {
border-color: #e5242b;
}
}
}
</style>
使用vue-preview实现
- 引入组件
npm i vue-preview -S
- 项目全局引入
import VuePreview from 'vue-preview'
Vue.use(VuePreview)
- 组件使用
<vue-preview :slides="listurl"></vue-preview>
// 数据
listurl:[
{
w:600,
h:400,
src:'https://dss2.bdstatic.com/8_V1bjqh_Q23odCf/pacific/1989771219.jpg',
msrc:'https://dss2.bdstatic.com/8_V1bjqh_Q23odCf/pacific/1989771219.jpg',
},
{
w:600,
h:400,
src:'https://dss2.bdstatic.com/8_V1bjqh_Q23odCf/pacific/1981772440.jpg',
msrc:'https://dss2.bdstatic.com/8_V1bjqh_Q23odCf/pacific/1981772440.jpg',
},
// w是预览时的大图的图片宽度,h属性是预览时的大图的图片高度。src是预览时大图的url,msrc属性是小图的url。
],
// css // 一行显示
<style lang="scss" scoped>
::v-deep .my-gallery{ //deep深层作用选择器
display: flex;
flex-wrap:wrap;//默认换行
figure{
width: 30%;
margin: 5px;
img{
width: 100%;
box-shadow: 0 0 8px #999;
border-radius: 5px;
}
}
}
</style>
3. 如果不想要某个按钮。比如分享按钮,可以使用css样式控制
::v-deep .pswp__top-bar .pswp__button--share{
display: none !important;
}
更多推荐
已为社区贡献9条内容
所有评论(0)