- 支持单/多张图翻页轮播
- 可全屏预览
- 自定义图片宽高
- 自定义无图提示语
- 自带图片加载loading
- 可将源码根据实际需求改造。
没安装 Element-UI 的可以将图片标签换为原生
效果图
全屏预览
单图,多图翻页轮播
使用
<image-preview :imgList="['url1', 'url2']"></image-preview>
源码
<template>
<div :class="['image-preview-wrapper', imgList.length ? 'has-border' : '']">
<!-- 有图 -->
<div v-if="imgList.length" class="banner-wrapper" :style="{ width: width + 'px', height: height + 'px' }" @click="isFullPreview = true">
<div class="banner-content" :style="{ left: left + 'px' }">
<el-image v-for="(item, index) in imgList" :key="index" :src="item" :style="{ width: width + 'px', height: height + 'px' }">
<div slot="placeholder" class="loading-placeholder">
正在加载中
</div>
</el-image>
</div>
</div>
<!-- 无图 -->
<div v-else class="no-img-box" :style="{ width: width - 2 + 'px', height: height - 2 + 'px' }">
<el-image :src="noImgUrl" class="no-img"></el-image>
<div v-show="noImgTip" class="no-img-tip">{{ noImgTip }}</div>
</div>
<!-- 多图切换 -->
<div v-if="imgList.length > 1" class="banner-btn-box">
<div :class="['banner-btn', currentIndex === 0 ? 'disabled-btn' : '']" @click="changeImg"><i class="el-icon-arrow-left"></i></div>
<div :class="['banner-btn', currentIndex === imgList.length - 1 ? 'disabled-btn' : '']" @click="changeImg('next')">
<i class="el-icon-arrow-right"></i>
</div>
<div class="view-img-index-text">{{ currentIndex + 1 }}/{{ imgList.length }}</div>
</div>
<!-- 大图全屏预览 -->
<div v-if="isFullPreview" class="full-preview-wrapper">
<div class="full-preview-content">
<div :class="['full-preview-btn', fullPreviewCurrentIndex === 0 ? 'disabled-btn' : '']" @click="changeImg"><i class="el-icon-arrow-left"></i></div>
<div class="banner-wrapper" :style="{ width: previewImgWidth + 'px', height: previewImgHeight + 'px' }" @click="isFullPreview = true">
<div class="banner-content" :style="{ left: fullPreviewLeft + 'px' }">
<el-image v-for="(item, index) in imgList" :key="index" :src="item" :style="{ width: previewImgWidth + 'px', height: previewImgHeight + 'px' }">
<div slot="placeholder" class="loading-placeholder">
正在加载中
</div>
</el-image>
</div>
</div>
<div :class="['full-preview-btn', fullPreviewCurrentIndex === imgList.length - 1 ? 'disabled-btn' : '']" @click="changeImg('next')">
<i class="el-icon-arrow-right"></i>
</div>
</div>
<div class="view-img-index-text">{{ fullPreviewCurrentIndex + 1 }}/{{ imgList.length }}</div>
<div class="full-preview-btn" @click="closeFullPreview">
<i class="el-icon-close"></i>
</div>
</div>
</div>
</template>
<script lang="ts">
import { Component, Prop, Vue, Watch } from 'vue-property-decorator';
@Component({ name: 'imagePreview' })
export default class ImagePreview extends Vue {
@Prop({ type: String, default: '200' }) private width!: string; // 自定义宽
@Prop({ type: String, default: '200' }) private height!: string; // 自定义高
@Prop({ type: String, default: '暂无图片' }) private noImgTip!: string; // 无图提示语
@Prop({ type: Array, default: () => [] }) private imgList!: string[]; // 图片列表
private noImgUrl: any = require('@/assets/404_images/404_img.png');
// 轮播图
private currentIndex = 0;
private left = 0;
// 全屏预览相关
private isFullPreview = false;
private fullPreviewCurrentIndex = 0;
private fullPreviewLeft = 0;
get previewImgWidth() {
return document.documentElement.clientHeight * 0.66;
}
get previewImgHeight() {
return this.previewImgWidth / (Number(this.width) / Number(this.height));
}
changeImg(direction = 'previous') {
let indexKey = 'currentIndex';
let leftKey = 'left';
let imgWidth = Number(this.width);
const isNext = direction === 'next';
if (this.isFullPreview) {
indexKey = 'fullPreviewCurrentIndex';
leftKey = 'fullPreviewLeft';
imgWidth = this.previewImgWidth;
}
if ((isNext && this[indexKey] !== this.imgList.length - 1) || (!isNext && this[indexKey] !== 0)) {
isNext ? this[indexKey]++ : this[indexKey]--;
this[leftKey] = this[indexKey] * imgWidth * -1;
}
}
closeFullPreview() {
this.isFullPreview = false;
this.fullPreviewCurrentIndex = 0;
this.fullPreviewLeft = 0;
}
@Watch('imgList', { deep: true, immediate: true })
watchImgListChange(val: string[]) {
this.currentIndex = 0;
this.left = 0;
this.fullPreviewCurrentIndex = 0;
this.fullPreviewLeft = 0;
}
}
</script>
<style lang="scss" scoped>
.image-preview-wrapper {
position: relative;
overflow: hidden;
border: 1px solid transparent;
cursor: default;
&.has-border:hover {
border: 1px solid #00b54b;
cursor: zoom-in;
}
// 轮播
.banner-wrapper {
overflow: hidden;
position: relative;
.banner-content {
position: absolute;
transition: left 0.5s;
display: flex;
.loading-placeholder {
width: 100%;
height: 100%;
display: flex;
background: #ededed;
justify-content: center;
align-items: center;
color: #b3b3b3;
}
}
}
// 无图
.no-img-box {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
border: 1px solid #ededed;
.no-img {
width: 50%;
}
.no-img-tip {
font-size: 14px;
color: #b3b3b3;
padding-top: 12px;
}
}
// 按钮
.banner-btn-box {
position: absolute;
left: 0;
right: 0;
bottom: 8px;
display: flex;
justify-content: center;
align-items: center;
.banner-btn {
width: 20px;
height: 20px;
line-height: 20px;
font-size: 12px;
text-align: center;
background: #000000;
opacity: 0.3;
color: #ffffff;
margin: 0 10px;
cursor: pointer;
border-radius: 5px;
&:hover {
opacity: 0.5;
}
}
.disabled-btn {
cursor: not-allowed;
background: #777777;
&:hover {
opacity: 0.5;
}
}
.view-img-index-text {
position: absolute;
right: 5px;
font-size: 12px;
opacity: 0.5;
}
}
// 全屏预览
.full-preview-wrapper {
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
z-index: 1001;
background: rgba(0, 0, 0, 0.5);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
cursor: default;
.full-preview-btn {
width: 48px;
height: 48px;
line-height: 48px;
background: #000000;
opacity: 0.6;
color: #ffffff;
font-size: 20px;
text-align: center;
// margin: 0 50px;
cursor: pointer;
border-radius: 50%;
&:hover {
opacity: 0.4;
}
&.disabled-btn {
cursor: not-allowed;
background: #777777;
&:hover {
opacity: 0.5;
}
}
}
.full-preview-content {
width: 90%;
display: flex;
align-items: center;
justify-content: space-around;
margin-bottom: 10px;
}
.view-img-index-text {
font-size: 16px;
color: #ffffff;
text-align: center;
margin-bottom: 10px;
}
}
}
</style>
API
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|
width | 自定义宽 | String | – | ‘200’ | height | 自定义高 | String | – | ‘200’ | noImgTip | 无图提示语 | String | – | ‘暂无图片’ | imgList | 图片Url列表 | Array | – | [] |
码字不易,觉得有帮助的小伙伴点个赞支持下~
扫描上方二维码关注我的订阅号~
|