Vue 单/多图片(可全屏预览)翻页轮播组件
支持单/多张图翻页轮播可全屏预览自定义图片宽高自定义无图提示语自带图片加载loading可将源码根据实际需求改造。效果图全屏预览单图,多图翻页轮播使用<image-preview :imgList="['url1', 'url2']"></image-preview>源码<template><div :class="['image-preview-wrap
·
- 支持单/多张图翻页轮播
- 可全屏预览
- 自定义图片宽高
- 自定义无图提示语
- 自带图片加载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 | – | [] |
码字不易,觉得有帮助的小伙伴点个赞支持下~
扫描上方二维码关注我的订阅号~
更多推荐
已为社区贡献16条内容
所有评论(0)